diff --git a/parity-crypto/CHANGELOG.md b/parity-crypto/CHANGELOG.md index 927c9dc9c..c915ee3c9 100644 --- a/parity-crypto/CHANGELOG.md +++ b/parity-crypto/CHANGELOG.md @@ -5,3 +5,9 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ ## [Unreleased] +- Remove `inv()` from `SecretKey` (breaking) +- `Generate::generate()` does not return error +- `Secp256k1` is no longer exported +- Remove `public_is_valid()` as it is now impossible to create invalid public keys +- 0-valued `Secp::Message`s are disallowed (signatures on them are forgeable for all keys) +- updates to upstream `rust-secp256k1` at v0.17.2 diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index d3e7b1994..5a7ea3b9b 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -16,13 +16,13 @@ required-features = ["publickey"] [dependencies] tiny-keccak = { version = "2.0", features = ["keccak"] } scrypt = { version = "0.2.0", default-features = false } -parity-secp256k1 = { version = "0.7.0", optional = true } +secp256k1 = { version = "0.17.2", optional = true, features = ["recovery", "rand-std"] } ethereum-types = { version = "0.8.0", optional = true } lazy_static = { version = "1.0", optional = true } ripemd160 = "0.8.0" sha2 = "0.8.0" -digest = "0.8.1" -hmac = "0.7.1" +digest = "0.8" +hmac = "0.7" aes = "0.3.2" aes-ctr = "0.3.0" block-modes = "0.3.3" @@ -40,4 +40,4 @@ hex-literal = "0.2.1" default = [] # public key crypto utils # moved from ethkey module in parity ethereum repository -publickey = ["parity-secp256k1", "lazy_static", "ethereum-types"] +publickey = ["secp256k1", "lazy_static", "ethereum-types"] diff --git a/parity-crypto/src/publickey/ec_math_utils.rs b/parity-crypto/src/publickey/ec_math_utils.rs index 1aa55db7e..bd8653b79 100644 --- a/parity-crypto/src/publickey/ec_math_utils.rs +++ b/parity-crypto/src/publickey/ec_math_utils.rs @@ -37,25 +37,20 @@ lazy_static! { pub static ref CURVE_ORDER: U256 = H256::from_slice(&SECP256K1_CURVE_ORDER).into_uint(); } -/// Whether the public key is valid. -pub fn public_is_valid(public: &Public) -> bool { - to_secp256k1_public(public).ok().map_or(false, |p| p.is_valid()) -} - /// In-place multiply public key by secret key (EC point * scalar) pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> { let key_secret = secret.to_secp256k1_secret()?; let mut key_public = to_secp256k1_public(public)?; - key_public.mul_assign(&SECP256K1, &key_secret)?; + key_public.mul_assign(&SECP256K1, &key_secret[..])?; set_public(public, &key_public); Ok(()) } /// In-place add one public key to another (EC point + EC point) pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> { - let mut key_public = to_secp256k1_public(public)?; + let key_public = to_secp256k1_public(public)?; let other_public = to_secp256k1_public(other)?; - key_public.add_assign(&SECP256K1, &other_public)?; + let key_public = key_public.combine(&other_public)?; set_public(public, &key_public); Ok(()) } @@ -63,10 +58,10 @@ pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> { /// In-place sub one public key from another (EC point - EC point) pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> { let mut key_neg_other = to_secp256k1_public(other)?; - key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?; + key_neg_other.mul_assign(&SECP256K1, super::MINUS_ONE_KEY)?; let mut key_public = to_secp256k1_public(public)?; - key_public.add_assign(&SECP256K1, &key_neg_other)?; + key_public = key_public.combine(&key_neg_other)?; set_public(public, &key_public); Ok(()) } @@ -74,15 +69,14 @@ pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> { /// Replace a public key with its additive inverse (EC point = - EC point) pub fn public_negate(public: &mut Public) -> Result<(), Error> { let mut key_public = to_secp256k1_public(public)?; - key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?; + key_public.mul_assign(&SECP256K1, super::MINUS_ONE_KEY)?; set_public(public, &key_public); Ok(()) } /// Return the generation point (aka base point) of secp256k1 pub fn generation_point() -> Public { - let public_key = - key::PublicKey::from_slice(&SECP256K1, &BASE_POINT_BYTES).expect("constructed using constants; qed"); + let public_key = key::PublicKey::from_slice(&BASE_POINT_BYTES).expect("constructed using constants; qed"); let mut public = Public::default(); set_public(&mut public, &public_key); public @@ -95,24 +89,24 @@ fn to_secp256k1_public(public: &Public) -> Result { temp }; - Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?) + Ok(key::PublicKey::from_slice(&public_data)?) } fn set_public(public: &mut Public, key_public: &key::PublicKey) { - let key_public_serialized = key_public.serialize_vec(&SECP256K1, false); + let key_public_serialized = key_public.serialize_uncompressed(); public.as_bytes_mut().copy_from_slice(&key_public_serialized[1..65]); } #[cfg(test)] mod tests { use super::super::{Generator, Random, Secret}; - use super::{generation_point, public_add, public_is_valid, public_mul_secret, public_negate, public_sub}; + use super::{generation_point, public_add, public_mul_secret, public_negate, public_sub}; use std::str::FromStr; #[test] fn public_addition_is_commutative() { - let public1 = Random.generate().unwrap().public().clone(); - let public2 = Random.generate().unwrap().public().clone(); + let public1 = Random.generate().public().clone(); + let public2 = Random.generate().public().clone(); let mut left = public1.clone(); public_add(&mut left, &public2).unwrap(); @@ -125,8 +119,8 @@ mod tests { #[test] fn public_addition_is_reversible_with_subtraction() { - let public1 = Random.generate().unwrap().public().clone(); - let public2 = Random.generate().unwrap().public().clone(); + let public1 = Random.generate().public().clone(); + let public2 = Random.generate().public().clone(); let mut sum = public1.clone(); public_add(&mut sum, &public2).unwrap(); @@ -137,7 +131,7 @@ mod tests { #[test] fn public_negation_is_involutory() { - let public = Random.generate().unwrap().public().clone(); + let public = Random.generate().public().clone(); let mut negation = public.clone(); public_negate(&mut negation).unwrap(); public_negate(&mut negation).unwrap(); @@ -145,12 +139,6 @@ mod tests { assert_eq!(negation, public); } - #[test] - fn known_public_is_valid() { - let public = Random.generate().unwrap().public().clone(); - assert!(public_is_valid(&public)); - } - #[test] fn generation_point_expected() { let point = generation_point(); diff --git a/parity-crypto/src/publickey/ecdh.rs b/parity-crypto/src/publickey/ecdh.rs index ab22c2a09..8cdaf793a 100644 --- a/parity-crypto/src/publickey/ecdh.rs +++ b/parity-crypto/src/publickey/ecdh.rs @@ -16,21 +16,37 @@ //! ECDH key agreement scheme implemented as a free function. -use super::{Error, Public, Secret, SECP256K1}; +use super::{Error, Public, Secret}; use secp256k1::{self, ecdh, key}; /// Agree on a shared secret pub fn agree(secret: &Secret, public: &Public) -> Result { - let context = &SECP256K1; let pdata = { let mut temp = [4u8; 65]; (&mut temp[1..65]).copy_from_slice(&public[0..64]); temp }; - let publ = key::PublicKey::from_slice(context, &pdata)?; - let sec = key::SecretKey::from_slice(context, secret.as_bytes())?; - let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); + let publ = key::PublicKey::from_slice(&pdata)?; + let sec = key::SecretKey::from_slice(secret.as_bytes())?; + let shared = ecdh::SharedSecret::new_with_hash(&publ, &sec, |x, _| x.into())?; Secret::import_key(&shared[0..32]).map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey)) } + +#[cfg(test)] +mod tests { + use super::{agree, Public, Secret}; + use std::str::FromStr; + + #[test] + fn test_agree() { + // Just some random values for secret/public to check we agree with previous implementation. + let secret = Secret::from_str("01a400760945613ff6a46383b250bf27493bfe679f05274916182776f09b28f1").unwrap(); + let public= Public::from_str("e37f3cbb0d0601dc930b8d8aa56910dd5629f2a0979cc742418960573efc5c0ff96bc87f104337d8c6ab37e597d4f9ffbd57302bc98a825519f691b378ce13f5").unwrap(); + let shared = agree(&secret, &public); + + assert!(shared.is_ok()); + assert_eq!(shared.unwrap().to_hex(), "28ab6fad6afd854ff27162e0006c3f6bd2daafc0816c85b5dfb05dbb865fa6ac",); + } +} diff --git a/parity-crypto/src/publickey/ecdsa_signature.rs b/parity-crypto/src/publickey/ecdsa_signature.rs index 6801adf10..ae245cffb 100644 --- a/parity-crypto/src/publickey/ecdsa_signature.rs +++ b/parity-crypto/src/publickey/ecdsa_signature.rs @@ -20,7 +20,10 @@ use super::{public_to_address, Address, Error, Message, Public, Secret, SECP256K use ethereum_types::{H256, H520}; use rustc_hex::{FromHex, ToHex}; use secp256k1::key::{PublicKey, SecretKey}; -use secp256k1::{Error as SecpError, Message as SecpMessage, RecoverableSignature, RecoveryId}; +use secp256k1::{ + recovery::{RecoverableSignature, RecoveryId}, + Error as SecpError, Message as SecpMessage, +}; use std::cmp::PartialEq; use std::fmt; use std::hash::{Hash, Hasher}; @@ -208,12 +211,12 @@ impl DerefMut for Signature { } /// Signs message with the given secret key. -/// Returns the corresponding signature +/// Returns the corresponding signature. pub fn sign(secret: &Secret, message: &Message) -> Result { let context = &SECP256K1; - let sec = SecretKey::from_slice(context, secret.as_ref())?; - let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?; - let (rec_id, data) = s.serialize_compact(context); + let sec = SecretKey::from_slice(secret.as_ref())?; + let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec); + let (rec_id, data) = s.serialize_compact(); let mut data_arr = [0; 65]; // no need to check if s is low, it always is @@ -225,9 +228,8 @@ pub fn sign(secret: &Secret, message: &Message) -> Result { /// Performs verification of the signature for the given message with corresponding public key pub fn verify_public(public: &Public, signature: &Signature, message: &Message) -> Result { let context = &SECP256K1; - let rsig = - RecoverableSignature::from_compact(context, &signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; - let sig = rsig.to_standard(context); + let rsig = RecoverableSignature::from_compact(&signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; + let sig = rsig.to_standard(); let pdata: [u8; 65] = { let mut temp = [4u8; 65]; @@ -235,7 +237,7 @@ pub fn verify_public(public: &Public, signature: &Signature, message: &Message) temp }; - let publ = PublicKey::from_slice(context, &pdata)?; + let publ = PublicKey::from_slice(&pdata)?; match context.verify(&SecpMessage::from_slice(&message[..])?, &sig, &publ) { Ok(_) => Ok(true), Err(SecpError::IncorrectSignature) => Ok(false), @@ -253,10 +255,9 @@ pub fn verify_address(address: &Address, signature: &Signature, message: &Messag /// Recovers the public key from the signature for the message pub fn recover(signature: &Signature, message: &Message) -> Result { let context = &SECP256K1; - let rsig = - RecoverableSignature::from_compact(context, &signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; + let rsig = RecoverableSignature::from_compact(&signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; let pubkey = context.recover(&SecpMessage::from_slice(&message[..])?, &rsig)?; - let serialized = pubkey.serialize_vec(context, false); + let serialized = pubkey.serialize_uncompressed(); let mut public = Public::default(); public.as_bytes_mut().copy_from_slice(&serialized[1..65]); @@ -272,9 +273,9 @@ mod tests { #[test] fn vrs_conversion() { // given - let keypair = Random.generate().unwrap(); - let message = Message::default(); - let signature = sign(keypair.secret(), &message).unwrap(); + let keypair = Random.generate(); + let message = Message::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + let signature = sign(keypair.secret(), &message).expect("can sign a non-zero message"); // when let vrs = signature.clone().into_electrum(); @@ -286,9 +287,9 @@ mod tests { #[test] fn signature_to_and_from_str() { - let keypair = Random.generate().unwrap(); - let message = Message::default(); - let signature = sign(keypair.secret(), &message).unwrap(); + let keypair = Random.generate(); + let message = Message::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + let signature = sign(keypair.secret(), &message).expect("can sign a non-zero message"); let string = format!("{}", signature); let deserialized = Signature::from_str(&string).unwrap(); assert_eq!(signature, deserialized); @@ -296,25 +297,25 @@ mod tests { #[test] fn sign_and_recover_public() { - let keypair = Random.generate().unwrap(); - let message = Message::default(); + let keypair = Random.generate(); + let message = Message::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); let signature = sign(keypair.secret(), &message).unwrap(); assert_eq!(keypair.public(), &recover(&signature, &message).unwrap()); } #[test] fn sign_and_verify_public() { - let keypair = Random.generate().unwrap(); - let message = Message::default(); - let signature = sign(keypair.secret(), &message).unwrap(); + let keypair = Random.generate(); + let message = Message::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + let signature = sign(keypair.secret(), &message).expect("can sign a non-zero message"); assert!(verify_public(keypair.public(), &signature, &message).unwrap()); } #[test] fn sign_and_verify_address() { - let keypair = Random.generate().unwrap(); - let message = Message::default(); - let signature = sign(keypair.secret(), &message).unwrap(); + let keypair = Random.generate(); + let message = Message::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + let signature = sign(keypair.secret(), &message).expect("can sign a non-zero message"); assert!(verify_address(&keypair.address(), &signature, &message).unwrap()); } } diff --git a/parity-crypto/src/publickey/ecies.rs b/parity-crypto/src/publickey/ecies.rs index 7b963c138..d7c1354f3 100644 --- a/parity-crypto/src/publickey/ecies.rs +++ b/parity-crypto/src/publickey/ecies.rs @@ -27,7 +27,7 @@ const ENC_VERSION: u8 = 0x04; /// /// Authenticated data may be empty. pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result, Error> { - let r = Random.generate()?; + let r = Random.generate(); let z = ecdh::agree(r.secret(), public)?; let mut key = [0u8; 32]; kdf(&z, &[0u8; 0], &mut key); @@ -122,7 +122,7 @@ mod tests { #[test] fn ecies_shared() { - let kp = Random.generate().unwrap(); + let kp = Random.generate(); let message = b"So many books, so little time"; let shared = b"shared"; diff --git a/parity-crypto/src/publickey/error.rs b/parity-crypto/src/publickey/error.rs index 322be394b..7f9bfb8e0 100644 --- a/parity-crypto/src/publickey/error.rs +++ b/parity-crypto/src/publickey/error.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -//! Module specific errors +//! Module specific errors. use crate::error::SymmError; use std::{error::Error as StdError, fmt, result}; diff --git a/parity-crypto/src/publickey/extended_keys.rs b/parity-crypto/src/publickey/extended_keys.rs index 40b33640e..44307fdf2 100644 --- a/parity-crypto/src/publickey/extended_keys.rs +++ b/parity-crypto/src/publickey/extended_keys.rs @@ -84,7 +84,7 @@ pub struct ExtendedSecret { impl ExtendedSecret { /// New extended key from given secret and chain code. pub fn with_code(secret: Secret, chain_code: H256) -> ExtendedSecret { - ExtendedSecret { secret: secret, chain_code: chain_code } + ExtendedSecret { secret, chain_code } } /// New extended key from given secret with the random chain code. @@ -93,7 +93,7 @@ impl ExtendedSecret { } /// New extended key from given secret. - /// Chain code will be derived from the secret itself (in a deterministic way). + /// Chain code will be derived from the secret itself (deterministically). pub fn new(secret: Secret) -> ExtendedSecret { let chain_code = derivation::chain_code(*secret); ExtendedSecret::with_code(secret, chain_code) @@ -263,10 +263,9 @@ mod derivation { let mut data = vec![0u8; 33 + T::len()]; let sec_private = - SecretKey::from_slice(&SECP256K1, private_key.as_bytes()).expect("Caller should provide valid private key"); - let sec_public = - PublicKey::from_secret_key(&SECP256K1, &sec_private).expect("Caller should provide valid private key"); - let public_serialized = sec_public.serialize_vec(&SECP256K1, true); + SecretKey::from_slice(private_key.as_bytes()).expect("Caller should provide valid private key"); + let sec_public = PublicKey::from_secret_key(&SECP256K1, &sec_private); + let public_serialized = sec_public.serialize(); // curve point (compressed public key) -- index // 0.33 -- 33..end @@ -319,8 +318,8 @@ mod derivation { let mut public_sec_raw = [0u8; 65]; public_sec_raw[0] = 4; public_sec_raw[1..65].copy_from_slice(public_key.as_bytes()); - let public_sec = PublicKey::from_slice(&SECP256K1, &public_sec_raw).map_err(|_| Error::InvalidPoint)?; - let public_serialized = public_sec.serialize_vec(&SECP256K1, true); + let public_sec = PublicKey::from_slice(&public_sec_raw).map_err(|_| Error::InvalidPoint)?; + let public_serialized = public_sec.serialize(); let mut data = vec![0u8; 33 + T::len()]; // curve point (compressed public key) -- index @@ -339,16 +338,15 @@ mod derivation { if *CURVE_ORDER <= new_private.into_uint() { return Err(Error::MissingIndex); } - let new_private_sec = SecretKey::from_slice(&SECP256K1, new_private.as_bytes()).expect( + let new_private_sec = SecretKey::from_slice(new_private.as_bytes()).expect( "Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed", ); - let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec) - .expect("Valid private key produces valid public key"); + let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec); // Adding two points on the elliptic curves (combining two public keys) - new_public.add_assign(&SECP256K1, &public_sec).expect("Addition of two valid points produce valid point"); + new_public = new_public.combine(&public_sec).expect("Addition of two valid points produce valid point"); - let serialized = new_public.serialize_vec(&SECP256K1, false); + let serialized = new_public.serialize_uncompressed(); Ok((H512::from_slice(&serialized[1..65]), new_chain_code)) } @@ -367,9 +365,9 @@ mod derivation { } pub fn point(secret: H256) -> Result { - let sec = SecretKey::from_slice(&SECP256K1, secret.as_bytes()).map_err(|_| Error::InvalidPoint)?; - let public_sec = PublicKey::from_secret_key(&SECP256K1, &sec).map_err(|_| Error::InvalidPoint)?; - let serialized = public_sec.serialize_vec(&SECP256K1, false); + let sec = SecretKey::from_slice(secret.as_bytes()).map_err(|_| Error::InvalidPoint)?; + let public_sec = PublicKey::from_secret_key(&SECP256K1, &sec); + let serialized = public_sec.serialize_uncompressed(); Ok(H512::from_slice(&serialized[1..65])) } @@ -490,7 +488,7 @@ mod tests { } #[test] - fn match_() { + fn test_key_derivation() { let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap(); let extended_secret = ExtendedSecret::with_code(secret.clone(), H256::from_low_u64_be(1)); let extended_public = ExtendedPublic::from_secret(&extended_secret).expect("Extended public should be created"); diff --git a/parity-crypto/src/publickey/keypair.rs b/parity-crypto/src/publickey/keypair.rs index a9dc05cab..d4fa13b39 100644 --- a/parity-crypto/src/publickey/keypair.rs +++ b/parity-crypto/src/publickey/keypair.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -//! Key pair (public + secrect) description +//! Key pair (public + secret) description. use super::{Address, Error, Public, Secret, SECP256K1}; use crate::Keccak256; @@ -48,14 +48,14 @@ impl KeyPair { /// Create a pair from secret key pub fn from_secret(secret: Secret) -> Result { let context = &SECP256K1; - let s: key::SecretKey = key::SecretKey::from_slice(context, &secret[..])?; - let pub_key = key::PublicKey::from_secret_key(context, &s)?; - let serialized = pub_key.serialize_vec(context, false); + let s: key::SecretKey = key::SecretKey::from_slice(&secret[..])?; + let pub_key = key::PublicKey::from_secret_key(context, &s); + let serialized = pub_key.serialize_uncompressed(); let mut public = Public::default(); public.as_bytes_mut().copy_from_slice(&serialized[1..65]); - let keypair = KeyPair { secret: secret, public: public }; + let keypair = KeyPair { secret, public }; Ok(keypair) } @@ -67,8 +67,7 @@ impl KeyPair { /// Copies a pair from another one pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self { - let context = &SECP256K1; - let serialized = publ.serialize_vec(context, false); + let serialized = publ.serialize_uncompressed(); let secret = Secret::from(sec); let mut public = Public::default(); public.as_bytes_mut().copy_from_slice(&serialized[1..65]); diff --git a/parity-crypto/src/publickey/keypair_generator.rs b/parity-crypto/src/publickey/keypair_generator.rs index 2ae91db6e..3afd86a97 100644 --- a/parity-crypto/src/publickey/keypair_generator.rs +++ b/parity-crypto/src/publickey/keypair_generator.rs @@ -17,29 +17,13 @@ //! Random key pair generator. Relies on the secp256k1 C-library to generate random data. use super::{Generator, KeyPair, SECP256K1}; -use rand::rngs::OsRng; -use std::convert::Infallible; /// Randomly generates new keypair, instantiating the RNG each time. pub struct Random; impl Generator for Random { - type Error = std::io::Error; - - fn generate(&mut self) -> Result { - match OsRng.generate() { - Ok(pair) => Ok(pair), - Err(void) => match void {}, // LLVM unreachable - } - } -} - -impl Generator for OsRng { - type Error = Infallible; - - fn generate(&mut self) -> Result { - let (sec, publ) = SECP256K1.generate_keypair(self).expect("context always created with full capabilities; qed"); - - Ok(KeyPair::from_keypair(sec, publ)) + fn generate(&mut self) -> KeyPair { + let (sec, publ) = SECP256K1.generate_keypair(&mut secp256k1::rand::thread_rng()); + KeyPair::from_keypair(sec, publ) } } diff --git a/parity-crypto/src/publickey/mod.rs b/parity-crypto/src/publickey/mod.rs index 12b07d176..8d487b5ad 100644 --- a/parity-crypto/src/publickey/mod.rs +++ b/parity-crypto/src/publickey/mod.rs @@ -28,7 +28,6 @@ pub mod ecdh; pub mod ecies; pub mod error; -pub use self::ec_math_utils::public_is_valid; pub use self::ecdsa_signature::{recover, sign, verify_address, verify_public, Signature}; pub use self::error::Error; pub use self::extended_keys::{Derivation, DerivationError, ExtendedKeyPair, ExtendedPublic, ExtendedSecret}; @@ -42,14 +41,18 @@ use lazy_static::lazy_static; pub use ethereum_types::{Address, Public}; pub type Message = H256; +/// The number -1 encoded as a secret key +const MINUS_ONE_KEY: &'static [u8] = &[ + 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, +]; + lazy_static! { - pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); + static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); } /// Generates new keypair. pub trait Generator { - type Error; - /// Should be called to generate new keypair. - fn generate(&mut self) -> Result; + fn generate(&mut self) -> KeyPair; } diff --git a/parity-crypto/src/publickey/secret_key.rs b/parity-crypto/src/publickey/secret_key.rs index e721ec66b..68522ca29 100644 --- a/parity-crypto/src/publickey/secret_key.rs +++ b/parity-crypto/src/publickey/secret_key.rs @@ -14,18 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -//! Secret key implementation +//! Secret key implementation. -use super::{Error, SECP256K1}; -use ethereum_types::H256; -use secp256k1::constants::SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE; -use secp256k1::key; use std::convert::TryFrom; use std::fmt; use std::ops::Deref; use std::str::FromStr; + +use ethereum_types::H256; +use secp256k1::constants::SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE; +use secp256k1::key; use zeroize::Zeroize; +use crate::publickey::Error; + /// Represents secret key #[derive(Clone, PartialEq, Eq)] pub struct Secret { @@ -74,7 +76,7 @@ impl Secret { /// Imports and validates the key. pub fn import_key(key: &[u8]) -> Result { - let secret = key::SecretKey::from_slice(&super::SECP256K1, key)?; + let secret = key::SecretKey::from_slice(key)?; Ok(secret.into()) } @@ -99,7 +101,7 @@ impl Secret { (false, false) => { let mut key_secret = self.to_secp256k1_secret()?; let other_secret = other.to_secp256k1_secret()?; - key_secret.add_assign(&SECP256K1, &other_secret)?; + key_secret.add_assign(&other_secret[..])?; *self = key_secret.into(); Ok(()) @@ -118,8 +120,8 @@ impl Secret { (false, false) => { let mut key_secret = self.to_secp256k1_secret()?; let mut other_secret = other.to_secp256k1_secret()?; - other_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?; - key_secret.add_assign(&SECP256K1, &other_secret)?; + other_secret.mul_assign(super::MINUS_ONE_KEY)?; + key_secret.add_assign(&other_secret[..])?; *self = key_secret.into(); Ok(()) @@ -131,12 +133,13 @@ impl Secret { pub fn dec(&mut self) -> Result<(), Error> { match self.is_zero() { true => { - *self = key::MINUS_ONE_KEY.into(); + *self = Secret::try_from(super::MINUS_ONE_KEY) + .expect("Constructing a secret key from a known-good constant works; qed."); Ok(()) } false => { let mut key_secret = self.to_secp256k1_secret()?; - key_secret.add_assign(&SECP256K1, &key::MINUS_ONE_KEY)?; + key_secret.add_assign(super::MINUS_ONE_KEY)?; *self = key_secret.into(); Ok(()) @@ -155,7 +158,7 @@ impl Secret { (false, false) => { let mut key_secret = self.to_secp256k1_secret()?; let other_secret = other.to_secp256k1_secret()?; - key_secret.mul_assign(&SECP256K1, &other_secret)?; + key_secret.mul_assign(&other_secret[..])?; *self = key_secret.into(); Ok(()) @@ -169,7 +172,7 @@ impl Secret { true => Ok(()), false => { let mut key_secret = self.to_secp256k1_secret()?; - key_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?; + key_secret.mul_assign(super::MINUS_ONE_KEY)?; *self = key_secret.into(); Ok(()) @@ -177,15 +180,6 @@ impl Secret { } } - /// Inplace inverse secret key (1 / scalar) - pub fn inv(&mut self) -> Result<(), Error> { - let mut key_secret = self.to_secp256k1_secret()?; - key_secret.inv_assign(&SECP256K1)?; - - *self = key_secret.into(); - Ok(()) - } - /// Compute power of secret key inplace (secret ^ pow). pub fn pow(&mut self, pow: usize) -> Result<(), Error> { if self.is_zero() { @@ -206,9 +200,9 @@ impl Secret { Ok(()) } - /// Create `secp256k1::key::SecretKey` based on this secret + /// Create a `secp256k1::key::SecretKey` based on this secret. pub fn to_secp256k1_secret(&self) -> Result { - Ok(key::SecretKey::from_slice(&SECP256K1, &self[..])?) + key::SecretKey::from_slice(&self[..]).map_err(Into::into) } } @@ -239,6 +233,17 @@ impl TryFrom<&str> for Secret { } } +impl TryFrom<&[u8]> for Secret { + type Error = Error; + + fn try_from(b: &[u8]) -> Result { + if b.len() != SECP256K1_SECRET_KEY_SIZE { + return Err(Error::InvalidSecretKey); + } + Ok(Self { inner: H256::from_slice(b) }) + } +} + impl From for Secret { fn from(key: key::SecretKey) -> Self { let mut a = [0; SECP256K1_SECRET_KEY_SIZE]; @@ -261,30 +266,9 @@ mod tests { use super::Secret; use std::str::FromStr; - #[test] - fn multiplicating_secret_inversion_with_secret_gives_one() { - let secret = Random.generate().unwrap().secret().clone(); - let mut inversion = secret.clone(); - inversion.inv().unwrap(); - inversion.mul(&secret).unwrap(); - assert_eq!( - inversion, - Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap() - ); - } - - #[test] - fn secret_inversion_is_reversible_with_inversion() { - let secret = Random.generate().unwrap().secret().clone(); - let mut inversion = secret.clone(); - inversion.inv().unwrap(); - inversion.inv().unwrap(); - assert_eq!(inversion, secret); - } - #[test] fn secret_pow() { - let secret = Random.generate().unwrap().secret().clone(); + let secret = Random.generate().secret().clone(); let mut pow0 = secret.clone(); pow0.pow(0).unwrap();