[BREAKING CHANGE] Make PK::from_secret_key() return a Result; change from_ffi functions to From impls
If you try to call PublicKey::from_secret() key with an incapable context it will now return an error. Before it would pass through to the underlying library which would terminate the process, something we strive to never expose. Also change the from_ffi functions on various types to impl's of From to be more Rustic. We cannot change the from_slice functions because they have error returns. Also add a Secp256k1::without_caps() function which creates a capability-less context. I find myself using this in so many places downstream that it seems appropriate.
This commit is contained in:
parent
b7d2b594e1
commit
c84cfb193f
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
|
|
||||||
name = "secp256k1"
|
name = "secp256k1"
|
||||||
version = "0.2.4"
|
version = "0.3.0"
|
||||||
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
|
authors = [ "Dawid Ciężarkiewicz <dpc@ucore.info>",
|
||||||
"Andrew Poelstra <apoelstra@wpsoftware.net>" ]
|
"Andrew Poelstra <apoelstra@wpsoftware.net>" ]
|
||||||
license = "CC0-1.0"
|
license = "CC0-1.0"
|
||||||
|
|
15
src/ecdh.rs
15
src/ecdh.rs
|
@ -38,12 +38,6 @@ impl SharedSecret {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new shared secret from a FFI shared secret
|
|
||||||
#[inline]
|
|
||||||
pub fn from_ffi(ss: ffi::SharedSecret) -> SharedSecret {
|
|
||||||
SharedSecret(ss)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtains a raw pointer suitable for use with FFI functions
|
/// Obtains a raw pointer suitable for use with FFI functions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_ptr(&self) -> *const ffi::SharedSecret {
|
pub fn as_ptr(&self) -> *const ffi::SharedSecret {
|
||||||
|
@ -51,6 +45,15 @@ impl SharedSecret {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new shared secret from a FFI shared secret
|
||||||
|
impl From<ffi::SharedSecret> for SharedSecret {
|
||||||
|
#[inline]
|
||||||
|
fn from(ss: ffi::SharedSecret) -> SharedSecret {
|
||||||
|
SharedSecret(ss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ops::Index<usize> for SharedSecret {
|
impl ops::Index<usize> for SharedSecret {
|
||||||
type Output = u8;
|
type Output = u8;
|
||||||
|
|
||||||
|
|
43
src/key.rs
43
src/key.rs
|
@ -22,8 +22,8 @@ use rand::Rng;
|
||||||
use serialize::{Decoder, Decodable, Encoder, Encodable};
|
use serialize::{Decoder, Decodable, Encoder, Encodable};
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
|
|
||||||
use super::Secp256k1;
|
use super::{Secp256k1, ContextFlag};
|
||||||
use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown};
|
use super::Error::{self, IncapableContext, InvalidPublicKey, InvalidSecretKey, Unknown};
|
||||||
use constants;
|
use constants;
|
||||||
use ffi;
|
use ffi;
|
||||||
|
|
||||||
|
@ -103,12 +103,6 @@ impl PublicKey {
|
||||||
PublicKey(ffi::PublicKey::new())
|
PublicKey(ffi::PublicKey::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new public key from a FFI public key
|
|
||||||
#[inline]
|
|
||||||
pub fn from_ffi(pk: ffi::PublicKey) -> PublicKey {
|
|
||||||
PublicKey(pk)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines whether a pubkey is valid
|
/// Determines whether a pubkey is valid
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
|
@ -127,7 +121,10 @@ impl PublicKey {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_secret_key(secp: &Secp256k1,
|
pub fn from_secret_key(secp: &Secp256k1,
|
||||||
sk: &SecretKey)
|
sk: &SecretKey)
|
||||||
-> PublicKey {
|
-> Result<PublicKey, Error> {
|
||||||
|
if secp.caps == ContextFlag::VerifyOnly || secp.caps == ContextFlag::None {
|
||||||
|
return Err(IncapableContext);
|
||||||
|
}
|
||||||
let mut pk = unsafe { ffi::PublicKey::blank() };
|
let mut pk = unsafe { ffi::PublicKey::blank() };
|
||||||
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
|
||||||
|
@ -135,7 +132,7 @@ impl PublicKey {
|
||||||
let res = ffi::secp256k1_ec_pubkey_create(secp.ctx, &mut pk, sk.as_ptr());
|
let res = ffi::secp256k1_ec_pubkey_create(secp.ctx, &mut pk, sk.as_ptr());
|
||||||
debug_assert_eq!(res, 1);
|
debug_assert_eq!(res, 1);
|
||||||
}
|
}
|
||||||
PublicKey(pk)
|
Ok(PublicKey(pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a public key directly from a slice
|
/// Creates a public key directly from a slice
|
||||||
|
@ -215,6 +212,15 @@ impl Decodable for PublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new public key from a FFI public key
|
||||||
|
impl From<ffi::PublicKey> for PublicKey {
|
||||||
|
#[inline]
|
||||||
|
fn from(pk: ffi::PublicKey) -> PublicKey {
|
||||||
|
PublicKey(pk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Encodable for PublicKey {
|
impl Encodable for PublicKey {
|
||||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
let secp = Secp256k1::with_caps(::ContextFlag::None);
|
let secp = Secp256k1::with_caps(::ContextFlag::None);
|
||||||
|
@ -277,7 +283,7 @@ impl Serialize for PublicKey {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::super::Secp256k1;
|
use super::super::Secp256k1;
|
||||||
use super::super::Error::{InvalidPublicKey, InvalidSecretKey};
|
use super::super::Error::{InvalidPublicKey, InvalidSecretKey, IncapableContext};
|
||||||
use super::{PublicKey, SecretKey};
|
use super::{PublicKey, SecretKey};
|
||||||
use super::super::constants;
|
use super::super::constants;
|
||||||
|
|
||||||
|
@ -337,6 +343,13 @@ mod test {
|
||||||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err());
|
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pubkey_from_slice_bad_context() {
|
||||||
|
let s = Secp256k1::without_caps();
|
||||||
|
let sk = SecretKey::new(&s, &mut thread_rng());
|
||||||
|
assert_eq!(PublicKey::from_secret_key(&s, &sk), Err(IncapableContext))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_deserialize() {
|
fn test_bad_deserialize() {
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
@ -554,15 +567,15 @@ mod test {
|
||||||
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap();
|
let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap();
|
||||||
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()).unwrap();
|
let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()).unwrap();
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk1), pk1);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk1).unwrap(), pk1);
|
||||||
assert!(sk1.add_assign(&s, &sk2).is_ok());
|
assert!(sk1.add_assign(&s, &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).unwrap(), pk1);
|
||||||
|
|
||||||
assert_eq!(PublicKey::from_secret_key(&s, &sk2), pk2);
|
assert_eq!(PublicKey::from_secret_key(&s, &sk2).unwrap(), pk2);
|
||||||
assert!(sk2.add_assign(&s, &sk1).is_ok());
|
assert!(sk2.add_assign(&s, &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).unwrap(), pk2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
48
src/lib.rs
48
src/lib.rs
|
@ -99,12 +99,6 @@ impl Signature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new public key from a FFI public key
|
|
||||||
#[inline]
|
|
||||||
pub fn from_ffi(sig: ffi::Signature) -> Signature {
|
|
||||||
Signature(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtains a raw pointer suitable for use with FFI functions
|
/// Obtains a raw pointer suitable for use with FFI functions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_ptr(&self) -> *const ffi::Signature {
|
pub fn as_ptr(&self) -> *const ffi::Signature {
|
||||||
|
@ -126,6 +120,15 @@ impl Signature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new signature from a FFI signature
|
||||||
|
impl From<ffi::Signature> for Signature {
|
||||||
|
#[inline]
|
||||||
|
fn from(sig: ffi::Signature) -> Signature {
|
||||||
|
Signature(sig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl RecoverableSignature {
|
impl RecoverableSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Converts a compact-encoded byte slice to a signature. This
|
/// Converts a compact-encoded byte slice to a signature. This
|
||||||
|
@ -146,12 +149,6 @@ impl RecoverableSignature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new public key from a FFI public key
|
|
||||||
#[inline]
|
|
||||||
pub fn from_ffi(sig: ffi::RecoverableSignature) -> RecoverableSignature {
|
|
||||||
RecoverableSignature(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtains a raw pointer suitable for use with FFI functions
|
/// Obtains a raw pointer suitable for use with FFI functions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_ptr(&self) -> *const ffi::RecoverableSignature {
|
pub fn as_ptr(&self) -> *const ffi::RecoverableSignature {
|
||||||
|
@ -184,6 +181,14 @@ impl RecoverableSignature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new recoverable signature from a FFI one
|
||||||
|
impl From<ffi::RecoverableSignature> for RecoverableSignature {
|
||||||
|
#[inline]
|
||||||
|
fn from(sig: ffi::RecoverableSignature) -> RecoverableSignature {
|
||||||
|
RecoverableSignature(sig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ops::Index<usize> for Signature {
|
impl ops::Index<usize> for Signature {
|
||||||
type Output = u8;
|
type Output = u8;
|
||||||
|
|
||||||
|
@ -345,6 +350,11 @@ impl Secp256k1 {
|
||||||
Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(flag) }, caps: caps }
|
Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(flag) }, caps: caps }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new Secp256k1 context with no capabilities (just de/serialization)
|
||||||
|
pub fn without_caps() -> Secp256k1 {
|
||||||
|
Secp256k1::with_caps(ContextFlag::None)
|
||||||
|
}
|
||||||
|
|
||||||
/// (Re)randomizes the Secp256k1 context for cheap sidechannel resistence;
|
/// (Re)randomizes the Secp256k1 context for cheap sidechannel resistence;
|
||||||
/// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell
|
/// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell
|
||||||
pub fn randomize<R: Rng>(&mut self, rng: &mut R) {
|
pub fn randomize<R: Rng>(&mut self, rng: &mut R) {
|
||||||
|
@ -370,12 +380,8 @@ impl Secp256k1 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn generate_keypair<R: Rng>(&self, rng: &mut R)
|
pub fn generate_keypair<R: Rng>(&self, rng: &mut R)
|
||||||
-> Result<(key::SecretKey, key::PublicKey), Error> {
|
-> Result<(key::SecretKey, key::PublicKey), Error> {
|
||||||
if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None {
|
|
||||||
return Err(Error::IncapableContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
let sk = key::SecretKey::new(self, rng);
|
let sk = key::SecretKey::new(self, rng);
|
||||||
let pk = key::PublicKey::from_secret_key(self, &sk);
|
let pk = try!(key::PublicKey::from_secret_key(self, &sk));
|
||||||
Ok((sk, pk))
|
Ok((sk, pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +401,7 @@ impl Secp256k1 {
|
||||||
sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
||||||
ptr::null()), 1);
|
ptr::null()), 1);
|
||||||
}
|
}
|
||||||
Ok(Signature::from_ffi(ret))
|
Ok(Signature::from(ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a signature for `msg` using the secret key `sk` and nonce `nonce`.
|
/// Constructs a signature for `msg` using the secret key `sk` and nonce `nonce`.
|
||||||
|
@ -414,7 +420,7 @@ impl Secp256k1 {
|
||||||
sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979,
|
||||||
ptr::null()), 1);
|
ptr::null()), 1);
|
||||||
}
|
}
|
||||||
Ok(RecoverableSignature::from_ffi(ret))
|
Ok(RecoverableSignature::from(ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the public key for which `sig` is a valid signature for
|
/// Determines the public key for which `sig` is a valid signature for
|
||||||
|
@ -434,7 +440,7 @@ impl Secp256k1 {
|
||||||
return Err(Error::InvalidSignature);
|
return Err(Error::InvalidSignature);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(key::PublicKey::from_ffi(pk))
|
Ok(key::PublicKey::from(pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
||||||
|
@ -636,7 +642,7 @@ mod tests {
|
||||||
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(&s, &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).unwrap();
|
let sig = s.sign(&msg, &key).unwrap();
|
||||||
let pk = PublicKey::from_secret_key(&s, &key);
|
let pk = PublicKey::from_secret_key(&s, &key).unwrap();
|
||||||
assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
|
assert_eq!(s.verify(&msg, &sig, &pk), Ok(()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue