diff --git a/src/ecdh.rs b/src/ecdh.rs index 3b116c9..bf58c1e 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -29,7 +29,7 @@ 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(secp: &Secp256k1, 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()); diff --git a/src/key.rs b/src/key.rs index bab85dd..c9ae24c 100644 --- a/src/key.rs +++ b/src/key.rs @@ -21,6 +21,8 @@ use std::mem; use super::{Secp256k1, ContextFlag}; use super::Error::{self, IncapableContext, InvalidPublicKey, InvalidSecretKey}; +use Signing; +use Verification; use constants; use ffi; @@ -63,7 +65,7 @@ impl SecretKey { /// Creates a new random secret key #[inline] #[cfg(any(test, feature = "rand"))] - pub fn new(secp: &Secp256k1, rng: &mut R) -> SecretKey { + pub fn new(secp: &Secp256k1, rng: &mut R) -> SecretKey { let mut data = random_32_bytes(rng); unsafe { while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 { @@ -75,7 +77,7 @@ impl SecretKey { /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key #[inline] - pub fn from_slice(secp: &Secp256k1, data: &[u8]) + pub fn from_slice(secp: &Secp256k1, data: &[u8]) -> Result { match data.len() { constants::SECRET_KEY_SIZE => { @@ -94,7 +96,7 @@ impl SecretKey { #[inline] /// Adds one secret key to another, modulo the curve order - pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey) + pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { unsafe { if ffi::secp256k1_ec_privkey_tweak_add(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 { @@ -107,7 +109,7 @@ impl SecretKey { #[inline] /// Multiplies one secret key by another, modulo the curve order - pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) + pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { unsafe { if ffi::secp256k1_ec_privkey_tweak_mul(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 { @@ -142,12 +144,9 @@ impl PublicKey { /// Creates a new public key from a secret key. #[inline] - pub fn from_secret_key(secp: &Secp256k1, + pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey) -> Result { - if secp.caps == ContextFlag::VerifyOnly || secp.caps == ContextFlag::None { - return Err(IncapableContext); - } let mut pk = unsafe { ffi::PublicKey::blank() }; unsafe { // We can assume the return value because it's not possible to construct @@ -160,7 +159,7 @@ impl PublicKey { /// Creates a public key directly from a slice #[inline] - pub fn from_slice(secp: &Secp256k1, data: &[u8]) + pub fn from_slice(secp: &Secp256k1, data: &[u8]) -> Result { let mut pk = unsafe { ffi::PublicKey::blank() }; @@ -179,7 +178,7 @@ 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::with_caps(ContextFlag::None); + let secp = Secp256k1::without_caps(); let mut ret = [0; constants::PUBLIC_KEY_SIZE]; unsafe { @@ -199,7 +198,7 @@ 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::with_caps(ContextFlag::None); + let secp = Secp256k1::without_caps(); let mut ret = [0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]; unsafe { @@ -219,11 +218,8 @@ impl PublicKey { #[inline] /// Adds the pk corresponding to `other` to the pk `self` in place - pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey) + pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { - if secp.caps == ContextFlag::SignOnly || secp.caps == ContextFlag::None { - return Err(IncapableContext); - } unsafe { if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0 as *mut _, other.as_ptr()) == 1 { @@ -236,11 +232,8 @@ impl PublicKey { #[inline] /// Muliplies the pk `self` in place by the scalar `other` - pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) + pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { - if secp.caps == ContextFlag::SignOnly || secp.caps == ContextFlag::None { - return Err(IncapableContext); - } unsafe { if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0 as *mut _, other.as_ptr()) == 1 { @@ -254,7 +247,7 @@ 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, secp: &Secp256k1, other: &PublicKey) -> Result { unsafe { let mut ret = mem::uninitialized(); let ptrs = [self.as_ptr(), other.as_ptr()]; @@ -577,7 +570,7 @@ mod test { assert!(pk2 <= pk1); assert!(!(pk2 < pk1)); assert!(!(pk1 < pk2)); - + assert!(pk3 < pk1); assert!(pk1 > pk3); assert!(pk3 <= pk1); diff --git a/src/lib.rs b/src/lib.rs index 41420c2..49eb9ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,7 @@ pub mod schnorr; pub use key::SecretKey; pub use key::PublicKey; +use std::marker::PhantomData; /// A tag used for recovering the public key from a compact signature #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -89,7 +90,7 @@ impl RecoveryId { impl Signature { #[inline] /// Converts a DER-encoded byte slice to a signature - pub fn from_der(secp: &Secp256k1, data: &[u8]) -> Result { + pub fn from_der(secp: &Secp256k1, data: &[u8]) -> Result { let mut ret = unsafe { ffi::Signature::blank() }; unsafe { @@ -103,7 +104,7 @@ 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(secp: &Secp256k1, data: &[u8]) -> Result { let mut ret = unsafe { ffi::Signature::blank() }; if data.len() != 64 { return Err(Error::InvalidSignature) @@ -123,7 +124,7 @@ 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(secp: &Secp256k1, data: &[u8]) -> Result { unsafe { let mut ret = ffi::Signature::blank(); if ffi::ecdsa_signature_parse_der_lax(secp.ctx, &mut ret, @@ -152,7 +153,7 @@ 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, secp: &Secp256k1) { unsafe { // Ignore return value, which indicates whether the sig // was already normalized. We don't care. @@ -175,7 +176,7 @@ impl Signature { #[inline] /// Serializes the signature in DER format - pub fn serialize_der(&self, secp: &Secp256k1) -> Vec { + pub fn serialize_der(&self, secp: &Secp256k1) -> Vec { let mut ret = Vec::with_capacity(72); let mut len: size_t = ret.capacity() as size_t; unsafe { @@ -189,7 +190,7 @@ impl Signature { #[inline] /// Serializes the signature in compact format - pub fn serialize_compact(&self, secp: &Secp256k1) -> [u8; 64] { + pub fn serialize_compact(&self, secp: &Secp256k1) -> [u8; 64] { let mut ret = [0; 64]; unsafe { let err = ffi::secp256k1_ecdsa_signature_serialize_compact(secp.ctx, ret.as_mut_ptr(), @@ -214,7 +215,7 @@ 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(secp: &Secp256k1, data: &[u8], recid: RecoveryId) -> Result { let mut ret = unsafe { ffi::RecoverableSignature::blank() }; unsafe { @@ -237,7 +238,7 @@ 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, secp: &Secp256k1) -> (RecoveryId, [u8; 64]) { let mut ret = [0u8; 64]; let mut recid = 0i32; unsafe { @@ -251,7 +252,7 @@ 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, secp: &Secp256k1) -> Signature { let mut ret = unsafe { ffi::Signature::blank() }; unsafe { let err = ffi::secp256k1_ecdsa_recoverable_signature_convert(secp.ctx, &mut ret, self.as_ptr()); @@ -376,14 +377,28 @@ impl error::Error for Error { } } +pub trait Signing {} +pub trait Verification {} + +pub struct None {} +pub struct SignOnly {} +pub struct VerifyOnly {} +pub struct All {} + +impl Signing for SignOnly {} +impl Signing for All {} + +impl Verification for VerifyOnly {} +impl Verification for All {} + /// The secp256k1 engine, used to execute all signature operations -pub struct Secp256k1 { +pub struct Secp256k1 { ctx: *mut ffi::Context, - caps: ContextFlag + phantom: PhantomData } -unsafe impl Send for Secp256k1 {} -unsafe impl Sync for Secp256k1 {} +unsafe impl Send for Secp256k1 {} +unsafe impl Sync for Secp256k1 {} /// Flags used to determine the capabilities of a `Secp256k1` object; /// the more capabilities, the more expensive it is to create. @@ -407,54 +422,56 @@ impl fmt::Display for ContextFlag { } } -impl Clone for Secp256k1 { - fn clone(&self) -> Secp256k1 { +impl Clone for Secp256k1 { + fn clone(&self) -> Secp256k1 { Secp256k1 { ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) }, - caps: self.caps + phantom: self.phantom } } } -impl PartialEq for Secp256k1 { - fn eq(&self, other: &Secp256k1) -> bool { self.caps == other.caps } -} -impl Eq for Secp256k1 { } - -impl fmt::Debug for Secp256k1 { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "Secp256k1 {{ [private], caps: {:?} }}", self.caps) - } +impl PartialEq for Secp256k1 { + fn eq(&self, other: &Secp256k1) -> bool { true } } -impl Drop for Secp256k1 { +impl Eq for Secp256k1 { } + +impl Drop for Secp256k1 { fn drop(&mut self) { unsafe { ffi::secp256k1_context_destroy(self.ctx); } } } -impl Secp256k1 { - /// Creates a new Secp256k1 context - #[inline] - pub fn new() -> Secp256k1 { - Secp256k1::with_caps(ContextFlag::Full) - } - - /// Creates a new Secp256k1 context with the specified capabilities - pub fn with_caps(caps: ContextFlag) -> Secp256k1 { - let flag = match caps { - ContextFlag::None => ffi::SECP256K1_START_NONE, - ContextFlag::SignOnly => ffi::SECP256K1_START_SIGN, - ContextFlag::VerifyOnly => ffi::SECP256K1_START_VERIFY, - ContextFlag::Full => ffi::SECP256K1_START_SIGN | ffi::SECP256K1_START_VERIFY - }; - Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(flag) }, caps: caps } - } - +impl Secp256k1 { /// Creates a new Secp256k1 context with no capabilities (just de/serialization) - pub fn without_caps() -> Secp256k1 { - Secp256k1::with_caps(ContextFlag::None) + 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 + pub fn new() -> Secp256k1 { + Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_SIGN | ffi::SECP256K1_START_VERIFY) }, phantom: PhantomData } + } +} + +impl Secp256k1 { + + pub fn signing_only() -> Secp256k1 { + Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_SIGN) }, phantom: PhantomData } + } +} + +impl Secp256k1 { + + pub fn verification_only() -> Secp256k1 { + Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(ffi::SECP256K1_START_VERIFY) }, phantom: PhantomData } + } +} + +impl Secp256k1 { /// (Re)randomizes the Secp256k1 context for cheap sidechannel resistence; /// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell @@ -476,25 +493,14 @@ impl Secp256k1 { } } - /// Generates a random keypair. Convenience function for `key::SecretKey::new` - /// and `key::PublicKey::from_secret_key`; call those functions directly for - /// batch key generation. Requires a signing-capable context. - #[inline] - #[cfg(any(test, feature = "rand"))] - pub fn generate_keypair(&self, rng: &mut R) - -> Result<(key::SecretKey, key::PublicKey), Error> { - let sk = key::SecretKey::new(self, rng); - let pk = try!(key::PublicKey::from_secret_key(self, &sk)); - Ok((sk, pk)) - } +} + +impl Secp256k1 { /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce /// Requires a signing-capable context. pub fn sign(&self, msg: &Message, sk: &key::SecretKey) -> Result { - if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } let mut ret = unsafe { ffi::Signature::blank() }; unsafe { @@ -510,10 +516,7 @@ impl Secp256k1 { /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce /// Requires a signing-capable context. pub fn sign_recoverable(&self, msg: &Message, sk: &key::SecretKey) - -> Result { - if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } + -> Result { let mut ret = unsafe { ffi::RecoverableSignature::blank() }; unsafe { @@ -526,13 +529,25 @@ impl Secp256k1 { Ok(RecoverableSignature::from(ret)) } + /// Generates a random keypair. Convenience function for `key::SecretKey::new` + /// and `key::PublicKey::from_secret_key`; call those functions directly for + /// batch key generation. Requires a signing-capable context. + #[inline] + #[cfg(any(test, feature = "rand"))] + pub fn generate_keypair(&self, rng: &mut R) + -> Result<(key::SecretKey, key::PublicKey), Error> { + let sk = key::SecretKey::new(self, rng); + let pk = try!(key::PublicKey::from_secret_key(self, &sk)); + Ok((sk, pk)) + } +} + +impl Secp256k1 { + /// Determines the public key for which `sig` is a valid signature for /// `msg`. Requires a verify-capable context. pub fn recover(&self, msg: &Message, sig: &RecoverableSignature) - -> Result { - if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } + -> Result { let mut pk = unsafe { ffi::PublicKey::blank() }; @@ -552,9 +567,6 @@ impl Secp256k1 { /// verify-capable context. #[inline] pub fn verify(&self, msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> { - if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } if !pk.is_valid() { Err(Error::InvalidPublicKey) @@ -567,14 +579,13 @@ impl Secp256k1 { } } - #[cfg(test)] mod tests { use rand::{Rng, thread_rng}; use key::{SecretKey, PublicKey}; use super::constants; - use super::{Secp256k1, Signature, RecoverableSignature, Message, RecoveryId, ContextFlag}; + use super::{Secp256k1, Signature, RecoverableSignature, Message, RecoveryId}; use super::Error::{InvalidMessage, InvalidPublicKey, IncorrectSignature, InvalidSignature, IncapableContext}; @@ -603,29 +614,23 @@ mod tests { #[test] fn capabilities() { - let none = Secp256k1::with_caps(ContextFlag::None); - let sign = Secp256k1::with_caps(ContextFlag::SignOnly); - let vrfy = Secp256k1::with_caps(ContextFlag::VerifyOnly); - let full = Secp256k1::with_caps(ContextFlag::Full); + let none = Secp256k1::without_caps(); + let sign = Secp256k1::signing_only(); + let vrfy = Secp256k1::verification_only(); + let full = Secp256k1::new(); let mut msg = [0u8; 32]; thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); // Try key generation - assert_eq!(none.generate_keypair(&mut thread_rng()), Err(IncapableContext)); - assert_eq!(vrfy.generate_keypair(&mut thread_rng()), Err(IncapableContext)); assert!(sign.generate_keypair(&mut thread_rng()).is_ok()); assert!(full.generate_keypair(&mut thread_rng()).is_ok()); let (sk, pk) = full.generate_keypair(&mut thread_rng()).unwrap(); // Try signing - assert_eq!(none.sign(&msg, &sk), Err(IncapableContext)); - assert_eq!(vrfy.sign(&msg, &sk), Err(IncapableContext)); assert!(sign.sign(&msg, &sk).is_ok()); assert!(full.sign(&msg, &sk).is_ok()); - assert_eq!(none.sign_recoverable(&msg, &sk), Err(IncapableContext)); - assert_eq!(vrfy.sign_recoverable(&msg, &sk), Err(IncapableContext)); assert!(sign.sign_recoverable(&msg, &sk).is_ok()); assert!(full.sign_recoverable(&msg, &sk).is_ok()); assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk)); @@ -634,14 +639,10 @@ mod tests { let sigr = full.sign_recoverable(&msg, &sk).unwrap(); // Try verifying - assert_eq!(none.verify(&msg, &sig, &pk), Err(IncapableContext)); - assert_eq!(sign.verify(&msg, &sig, &pk), Err(IncapableContext)); assert!(vrfy.verify(&msg, &sig, &pk).is_ok()); assert!(full.verify(&msg, &sig, &pk).is_ok()); // Try pk recovery - assert_eq!(none.recover(&msg, &sigr), Err(IncapableContext)); - assert_eq!(sign.recover(&msg, &sigr), Err(IncapableContext)); assert!(vrfy.recover(&msg, &sigr).is_ok()); assert!(full.recover(&msg, &sigr).is_ok()); diff --git a/src/schnorr.rs b/src/schnorr.rs index d20cbbc..e229f4f 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -19,13 +19,15 @@ use ContextFlag; use Error; use Message; use Secp256k1; +use Signing; use constants; use ffi; -use key::{SecretKey, PublicKey}; +use key::{PublicKey, SecretKey}; -use std::{mem, ptr}; +use Verification; use std::convert::From; +use std::{mem, ptr}; /// A Schnorr signature. pub struct Signature([u8; constants::SCHNORR_SIGNATURE_SIZE]); @@ -47,35 +49,41 @@ impl Signature { } } -impl Secp256k1 { +impl Secp256k1 { /// Create a Schnorr signature pub fn sign_schnorr(&self, msg: &Message, sk: &SecretKey) -> Result { - if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } - let mut ret: Signature = unsafe { mem::uninitialized() }; unsafe { // We can assume the return value because it's not possible to construct // an invalid signature from a valid `Message` and `SecretKey` - let err = ffi::secp256k1_schnorr_sign(self.ctx, ret.as_mut_ptr(), msg.as_ptr(), - sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979, - ptr::null()); + let err = ffi::secp256k1_schnorr_sign( + self.ctx, + ret.as_mut_ptr(), + msg.as_ptr(), + sk.as_ptr(), + ffi::secp256k1_nonce_function_rfc6979, + ptr::null(), + ); debug_assert_eq!(err, 1); } Ok(ret) } +} +impl Secp256k1 { /// Verify a Schnorr signature - pub fn verify_schnorr(&self, msg: &Message, sig: &Signature, pk: &PublicKey) -> Result<(), Error> { - if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } - + pub fn verify_schnorr( + &self, + msg: &Message, + sig: &Signature, + pk: &PublicKey, + ) -> Result<(), Error> { if !pk.is_valid() { Err(Error::InvalidPublicKey) - } else if unsafe { ffi::secp256k1_schnorr_verify(self.ctx, sig.as_ptr(), msg.as_ptr(), - pk.as_ptr()) } == 0 { + } else if unsafe { + ffi::secp256k1_schnorr_verify(self.ctx, sig.as_ptr(), msg.as_ptr(), pk.as_ptr()) + } == 0 + { Err(Error::IncorrectSignature) } else { Ok(()) @@ -84,16 +92,10 @@ impl Secp256k1 { /// Retrieves the public key for which `sig` is a valid signature for `msg`. /// Requires a verify-capable context. - pub fn recover_schnorr(&self, msg: &Message, sig: &Signature) - -> Result { - if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { - return Err(Error::IncapableContext); - } - + pub fn recover_schnorr(&self, msg: &Message, sig: &Signature) -> Result { let mut pk = unsafe { ffi::PublicKey::blank() }; unsafe { - if ffi::secp256k1_schnorr_recover(self.ctx, &mut pk, - sig.as_ptr(), msg.as_ptr()) != 1 { + if ffi::secp256k1_schnorr_recover(self.ctx, &mut pk, sig.as_ptr(), msg.as_ptr()) != 1 { return Err(Error::InvalidSignature); } };