From d97775542aa09a98fd8dab63b2232d45d8949431 Mon Sep 17 00:00:00 2001
From: Gavin Wood <gavin@parity.io>
Date: Thu, 24 Oct 2019 10:59:09 +0200
Subject: [PATCH] Add SECP256k1/ECDSA support for transaction signing (#3861)

* Add SECP256k1/ECDSA support for transaction signing.

* Refactoring and fixes

* Fix for contracts

* Avoid breaking runtime host function

* Build fixes, make subkey work more generaically.

* Fix tests

* Dedpulicate a bit of code, remove unneeded code, docs

* Bump runtime version

* Fix a test and clean up some code.

* Derivation can derive seed.

* Whitespace

* Bump runtime again.

* Update core/primitives/src/crypto.rs

Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Update core/primitives/src/ecdsa.rs

Co-Authored-By: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Fix AppVerify
---
 substrate/Cargo.lock                          |   2 +
 substrate/core/application-crypto/src/lib.rs  |  13 +-
 .../core/application-crypto/src/traits.rs     |   1 +
 substrate/core/executor/src/host_interface.rs |  82 ++-
 substrate/core/keyring/src/ed25519.rs         |  15 +
 substrate/core/keyring/src/sr25519.rs         |  15 +
 substrate/core/primitives/Cargo.toml          |   4 +
 substrate/core/primitives/src/crypto.rs       | 286 +++++---
 substrate/core/primitives/src/ecdsa.rs        | 608 ++++++++++++++++++
 substrate/core/primitives/src/ed25519.rs      |  20 +-
 substrate/core/primitives/src/hexdisplay.rs   |   2 +-
 substrate/core/primitives/src/lib.rs          |   1 +
 substrate/core/primitives/src/sr25519.rs      |  53 +-
 substrate/core/sr-io/src/lib.rs               |   9 +-
 substrate/core/sr-io/with_std.rs              |  10 +
 substrate/core/sr-io/without_std.rs           |  24 +
 .../src/generic/unchecked_extrinsic.rs        |  22 +-
 substrate/core/sr-primitives/src/lib.rs       |  60 +-
 substrate/core/sr-primitives/src/traits.rs    |  73 ++-
 substrate/node/cli/src/chain_spec.rs          |  67 +-
 substrate/node/cli/src/factory_impl.rs        |  13 +-
 substrate/node/cli/src/service.rs             |  17 +-
 substrate/node/primitives/src/lib.rs          |   9 +-
 substrate/node/runtime/src/lib.rs             |  59 +-
 substrate/node/testing/src/keyring.rs         |   6 +-
 substrate/srml/system/src/offchain.rs         |  71 +-
 substrate/subkey/src/cli.yml                  |   5 +
 substrate/subkey/src/main.rs                  | 146 +++--
 substrate/subkey/src/vanity.rs                |   6 +-
 .../test-utils/chain-spec-builder/src/main.rs |   6 +-
 30 files changed, 1286 insertions(+), 419 deletions(-)
 create mode 100644 substrate/core/primitives/src/ecdsa.rs

diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index a87da6586cc..14f8c87c1aa 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -5366,6 +5366,7 @@ dependencies = [
  "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "impl-serde 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libsecp256k1 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -5385,6 +5386,7 @@ dependencies = [
  "substrate-primitives-storage 2.0.0",
  "substrate-serializer 2.0.0",
  "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/substrate/core/application-crypto/src/lib.rs b/substrate/core/application-crypto/src/lib.rs
index 16eda532383..b4ada5425b4 100644
--- a/substrate/core/application-crypto/src/lib.rs
+++ b/substrate/core/application-crypto/src/lib.rs
@@ -88,22 +88,13 @@ macro_rules! app_crypto {
 			}
 			fn derive<
 				Iter: Iterator<Item=$crate::DeriveJunction>
-			>(&self, path: Iter) -> Result<Self, Self::DeriveError> {
-				self.0.derive(path).map(Self)
+			>(&self, path: Iter, seed: Option<Self::Seed>) -> Result<(Self, Option<Self::Seed>), Self::DeriveError> {
+				self.0.derive(path, seed).map(|x| (Self(x.0), x.1))
 			}
 			fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) }
 			fn from_seed_slice(seed: &[u8]) -> Result<Self, $crate::SecretStringError> {
 				<$pair>::from_seed_slice(seed).map(Self)
 			}
-			fn from_standard_components<
-				I: Iterator<Item=$crate::DeriveJunction>
-			>(
-				seed: &str,
-				password: Option<&str>,
-				path: I,
-			) -> Result<Self, $crate::SecretStringError> {
-				<$pair>::from_standard_components::<I>(seed, password, path).map(Self)
-			}
 			fn sign(&self, msg: &[u8]) -> Self::Signature {
 				Signature(self.0.sign(msg))
 			}
diff --git a/substrate/core/application-crypto/src/traits.rs b/substrate/core/application-crypto/src/traits.rs
index 49d3a44aee3..66e6cd6579b 100644
--- a/substrate/core/application-crypto/src/traits.rs
+++ b/substrate/core/application-crypto/src/traits.rs
@@ -126,3 +126,4 @@ pub trait RuntimeAppPublic: Sized  {
 	/// Verify that the given signature matches the given message using this public key.
 	fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool;
 }
+
diff --git a/substrate/core/executor/src/host_interface.rs b/substrate/core/executor/src/host_interface.rs
index e6386ff1acc..7d87d93333f 100644
--- a/substrate/core/executor/src/host_interface.rs
+++ b/substrate/core/executor/src/host_interface.rs
@@ -41,6 +41,40 @@ macro_rules! debug_trace {
 
 pub struct SubstrateExternals;
 
+enum RecoverResult {
+	Invalid(u32),
+	Valid(secp256k1::PublicKey),
+}
+
+fn secp256k1_recover(
+	context: &mut dyn FunctionContext,
+	msg_data: Pointer<u8>,
+	sig_data: Pointer<u8>,
+) -> WResult<RecoverResult> {
+	let mut sig = [0u8; 65];
+	context.read_memory_into(sig_data, &mut sig[..])
+		.map_err(|_| "Invalid attempt to get signature in ext_secp256k1_ecdsa_recover")?;
+	let rs = match secp256k1::Signature::parse_slice(&sig[0..64]) {
+		Ok(rs) => rs,
+		_ => return Ok(RecoverResult::Invalid(1)),
+	};
+
+	let recovery_id = if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8;
+	let v = match secp256k1::RecoveryId::parse(recovery_id) {
+		Ok(v) => v,
+		_ => return Ok(RecoverResult::Invalid(2)),
+	};
+
+	let mut msg = [0u8; 32];
+	context.read_memory_into(msg_data, &mut msg[..])
+		.map_err(|_| "Invalid attempt to get message in ext_secp256k1_ecdsa_recover")?;
+
+	Ok(match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) {
+		Ok(pubkey) => RecoverResult::Valid(pubkey),
+		Err(_) => RecoverResult::Invalid(3),
+	})
+}
+
 impl_wasm_host_interface! {
 	impl SubstrateExternals where context {
 		ext_malloc(size: WordSize) -> Pointer<u8> {
@@ -781,33 +815,29 @@ impl_wasm_host_interface! {
 			sig_data: Pointer<u8>,
 			pubkey_data: Pointer<u8>,
 		) -> u32 {
-			let mut sig = [0u8; 65];
-			context.read_memory_into(sig_data, &mut sig[..])
-				.map_err(|_| "Invalid attempt to get signature in ext_secp256k1_ecdsa_recover")?;
-			let rs = match secp256k1::Signature::parse_slice(&sig[0..64]) {
-				Ok(rs) => rs,
-				_ => return Ok(1),
-			};
-
-			let recovery_id = if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8;
-			let v = match secp256k1::RecoveryId::parse(recovery_id) {
-				Ok(v) => v,
-				_ => return Ok(2),
-			};
-
-			let mut msg = [0u8; 32];
-			context.read_memory_into(msg_data, &mut msg[..])
-				.map_err(|_| "Invalid attempt to get message in ext_secp256k1_ecdsa_recover")?;
-
-			let pubkey = match secp256k1::recover(&secp256k1::Message::parse(&msg), &rs, &v) {
-				Ok(pk) => pk,
-				_ => return Ok(3),
-			};
-
-			context.write_memory(pubkey_data, &pubkey.serialize()[1..65])
-				.map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?;
+			match secp256k1_recover(context, msg_data, sig_data)? {
+				RecoverResult::Invalid(c) => Ok(c),
+				RecoverResult::Valid(pubkey) => {
+					context.write_memory(pubkey_data, &pubkey.serialize()[1..65])
+						.map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?;
+					Ok(0)
+				}
+			}
+		}
 
-			Ok(0)
+		ext_secp256k1_ecdsa_recover_compressed(
+			msg_data: Pointer<u8>,
+			sig_data: Pointer<u8>,
+			pubkey_data: Pointer<u8>,
+		) -> u32 {
+			match secp256k1_recover(context, msg_data, sig_data)? {
+				RecoverResult::Invalid(c) => Ok(c),
+				RecoverResult::Valid(pubkey) => {
+					context.write_memory(pubkey_data, &pubkey.serialize_compressed()[..])
+						.map_err(|_| "Invalid attempt to set pubkey in ext_secp256k1_ecdsa_recover")?;
+					Ok(0)
+				}
+			}
 		}
 
 		ext_is_validator() -> u32 {
diff --git a/substrate/core/keyring/src/ed25519.rs b/substrate/core/keyring/src/ed25519.rs
index 56bdb1ce8c0..c1a357fc0e4 100644
--- a/substrate/core/keyring/src/ed25519.rs
+++ b/substrate/core/keyring/src/ed25519.rs
@@ -20,6 +20,7 @@ use std::{collections::HashMap, ops::Deref};
 use lazy_static::lazy_static;
 use primitives::{ed25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256};
 pub use primitives::ed25519;
+use sr_primitives::AccountId32;
 
 /// Set of test accounts.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::Display, strum_macros::EnumIter)]
@@ -39,6 +40,10 @@ impl Keyring {
 		Self::iter().find(|&k| &Public::from(k) == who)
 	}
 
+	pub fn from_account_id(who: &AccountId32) -> Option<Keyring> {
+		Self::iter().find(|&k| &k.to_account_id() == who)
+	}
+
 	pub fn from_raw_public(who: [u8; 32]) -> Option<Keyring> {
 		Self::from_public(&Public::from_raw(who))
 	}
@@ -59,6 +64,10 @@ impl Keyring {
 		Public::from(self).to_raw_vec()
 	}
 
+	pub fn to_account_id(self) -> AccountId32 {
+		self.to_raw_public().into()
+	}
+
 	pub fn sign(self, msg: &[u8]) -> Signature {
 		Pair::from(self).sign(msg)
 	}
@@ -119,6 +128,12 @@ impl From<Keyring> for Public {
 	}
 }
 
+impl From<Keyring> for AccountId32 {
+	fn from(k: Keyring) -> Self {
+		k.to_account_id()
+	}
+}
+
 impl From<Keyring> for Pair {
 	fn from(k: Keyring) -> Self {
 		k.pair()
diff --git a/substrate/core/keyring/src/sr25519.rs b/substrate/core/keyring/src/sr25519.rs
index bb3aaa6b51d..b37b2bdf9b2 100644
--- a/substrate/core/keyring/src/sr25519.rs
+++ b/substrate/core/keyring/src/sr25519.rs
@@ -21,6 +21,7 @@ use std::ops::Deref;
 use lazy_static::lazy_static;
 use primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256};
 pub use primitives::sr25519;
+use sr_primitives::AccountId32;
 
 /// Set of test accounts.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::Display, strum_macros::EnumIter)]
@@ -40,6 +41,10 @@ impl Keyring {
 		Self::iter().find(|&k| &Public::from(k) == who)
 	}
 
+	pub fn from_account_id(who: &AccountId32) -> Option<Keyring> {
+		Self::iter().find(|&k| &k.to_account_id() == who)
+	}
+
 	pub fn from_raw_public(who: [u8; 32]) -> Option<Keyring> {
 		Self::from_public(&Public::from_raw(who))
 	}
@@ -60,6 +65,10 @@ impl Keyring {
 		Public::from(self).to_raw_vec()
 	}
 
+	pub fn to_account_id(self) -> AccountId32 {
+		self.to_raw_public().into()
+	}
+
 	pub fn sign(self, msg: &[u8]) -> Signature {
 		Pair::from(self).sign(msg)
 	}
@@ -114,6 +123,12 @@ lazy_static! {
 	};
 }
 
+impl From<Keyring> for AccountId32 {
+	fn from(k: Keyring) -> Self {
+		k.to_account_id()
+	}
+}
+
 impl From<Keyring> for Public {
 	fn from(k: Keyring) -> Self {
 		(*PUBLIC_KEYS).get(&k).unwrap().clone()
diff --git a/substrate/core/primitives/Cargo.toml b/substrate/core/primitives/Cargo.toml
index 557ce55b883..bc8106de3ab 100644
--- a/substrate/core/primitives/Cargo.toml
+++ b/substrate/core/primitives/Cargo.toml
@@ -31,6 +31,8 @@ num-traits = { version = "0.2.8", default-features = false }
 zeroize = "0.10.1"
 lazy_static = { version = "1.4.0", optional = true }
 parking_lot = { version = "0.9.0", optional = true }
+libsecp256k1 = { version = "0.3.0", optional = true }
+tiny-keccak = { version = "1.5.0", optional = true }
 substrate-debug-derive = { version = "2.0.0", path = "./debug-derive" }
 externalities = { package = "substrate-externalities", path = "../externalities", optional = true }
 primitives-storage = { package = "substrate-primitives-storage", path = "storage", default-features = false }
@@ -82,6 +84,8 @@ std = [
 	"schnorrkel",
 	"regex",
 	"num-traits/std",
+	"libsecp256k1",
+	"tiny-keccak",
 	"substrate-debug-derive/std",
 	"externalities",
 	"primitives-storage/std",
diff --git a/substrate/core/primitives/src/crypto.rs b/substrate/core/primitives/src/crypto.rs
index 588f3bc6e27..b7c70e62247 100644
--- a/substrate/core/primitives/src/crypto.rs
+++ b/substrate/core/primitives/src/crypto.rs
@@ -255,7 +255,7 @@ pub enum PublicError {
 
 /// Key that can be encoded to/from SS58.
 #[cfg(feature = "std")]
-pub trait Ss58Codec: Sized {
+pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
 	/// Some if the string is a properly encoded SS58Check address.
 	fn from_ss58check(s: &str) -> Result<Self, PublicError> {
 		Self::from_ss58check_with_version(s)
@@ -269,7 +269,23 @@ pub trait Ss58Codec: Sized {
 			})
 	}
 	/// Some if the string is a properly encoded SS58Check address.
-	fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError>;
+	fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
+		let mut res = Self::default();
+		let len = res.as_mut().len();
+		let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
+		if d.len() != len + 3 {
+			// Invalid length.
+			return Err(PublicError::BadLength);
+		}
+		let ver = d[0].try_into().map_err(|_: ()| PublicError::UnknownVersion)?;
+
+		if d[len + 1..len + 3] != ss58hash(&d[0..len + 1]).as_bytes()[0..2] {
+			// Invalid checksum.
+			return Err(PublicError::InvalidChecksum);
+		}
+		res.as_mut().copy_from_slice(&d[1..len + 1]);
+		Ok((res, ver))
+	}
 	/// Some if the string is a properly encoded SS58Check address, optionally with
 	/// a derivation path following.
 	fn from_string(s: &str) -> Result<Self, PublicError> {
@@ -285,7 +301,13 @@ pub trait Ss58Codec: Sized {
 	}
 
 	/// Return the ss58-check string for this key.
-	fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String;
+	fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String {
+		let mut v = vec![version.into()];
+		v.extend(self.as_ref());
+		let r = ss58hash(&v);
+		v.extend(&r.as_bytes()[0..2]);
+		v.to_base58()
+	}
 	/// Return the ss58-check string for this key.
 	fn to_ss58check(&self) -> String { self.to_ss58check_with_version(*DEFAULT_VERSION.lock()) }
 	/// Some if the string is a properly encoded SS58Check address, optionally with
@@ -408,44 +430,28 @@ pub fn set_default_ss58_version(version: Ss58AddressFormat) {
 }
 
 #[cfg(feature = "std")]
-impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
-	fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
-		let mut res = T::default();
-		let len = res.as_mut().len();
-		let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
-		if d.len() != len + 3 {
-			// Invalid length.
-			return Err(PublicError::BadLength);
-		}
-		let ver = d[0].try_into().map_err(|_: ()| PublicError::UnknownVersion)?;
-
-		if d[len+1..len+3] != ss58hash(&d[0..len+1]).as_bytes()[0..2] {
-			// Invalid checksum.
-			return Err(PublicError::InvalidChecksum);
-		}
-		res.as_mut().copy_from_slice(&d[1..len+1]);
-		Ok((res, ver))
-	}
-
-	fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String {
-		let mut v = vec![version.into()];
-		v.extend(self.as_ref());
-		let r = ss58hash(&v);
-		v.extend(&r.as_bytes()[0..2]);
-		v.to_base58()
-	}
-
+impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
 	fn from_string(s: &str) -> Result<Self, PublicError> {
-		let re = Regex::new(r"^(?P<ss58>[\w\d]+)?(?P<path>(//?[^/]+)*)$")
+		let re = Regex::new(r"^(?P<ss58>[\w\d ]+)?(?P<path>(//?[^/]+)*)$")
 			.expect("constructed from known-good static value; qed");
 		let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?;
 		let re_junction = Regex::new(r"/(/?[^/]+)")
 			.expect("constructed from known-good static value; qed");
-		let addr = Self::from_ss58check(
-			cap.name("ss58")
-				.map(|r| r.as_str())
-				.unwrap_or(DEV_ADDRESS)
-		)?;
+		let s = cap.name("ss58")
+			.map(|r| r.as_str())
+			.unwrap_or(DEV_ADDRESS);
+		let addr = if s.starts_with("0x") {
+			let d = hex::decode(&s[2..]).map_err(|_| PublicError::InvalidFormat)?;
+			let mut r = Self::default();
+			if d.len() == r.as_ref().len() {
+				r.as_mut().copy_from_slice(&d);
+				r
+			} else {
+				Err(PublicError::BadLength)?
+			}
+		} else {
+			Self::from_ss58check(s)?
+		};
 		if cap["path"].is_empty() {
 			Ok(addr)
 		} else {
@@ -457,7 +463,7 @@ impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
 	}
 
 	fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
-		let re = Regex::new(r"^(?P<ss58>[\w\d]+)?(?P<path>(//?[^/]+)*)$")
+		let re = Regex::new(r"^(?P<ss58>[\w\d ]+)?(?P<path>(//?[^/]+)*)$")
 			.expect("constructed from known-good static value; qed");
 		let cap = re.captures(s).ok_or(PublicError::InvalidFormat)?;
 		let re_junction = Regex::new(r"/(/?[^/]+)")
@@ -495,6 +501,103 @@ pub trait Public: AsRef<[u8]> + AsMut<[u8]> + Default + Derive + CryptoType + Pa
 	fn as_slice(&self) -> &[u8] { self.as_ref() }
 }
 
+/// An opaque 32-byte cryptographic identifier.
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode)]
+pub struct AccountId32([u8; 32]);
+
+impl UncheckedFrom<crate::hash::H256> for AccountId32 {
+	fn unchecked_from(h: crate::hash::H256) -> Self {
+		AccountId32(h.into())
+	}
+}
+
+#[cfg(feature = "std")]
+impl Ss58Codec for AccountId32 {}
+
+impl AsRef<[u8]> for AccountId32 {
+	fn as_ref(&self) -> &[u8] {
+		&self.0[..]
+	}
+}
+
+impl AsMut<[u8]> for AccountId32 {
+	fn as_mut(&mut self) -> &mut [u8] {
+		&mut self.0[..]
+	}
+}
+
+impl AsRef<[u8; 32]> for AccountId32 {
+	fn as_ref(&self) -> &[u8; 32] {
+		&self.0
+	}
+}
+
+impl AsMut<[u8; 32]> for AccountId32 {
+	fn as_mut(&mut self) -> &mut [u8; 32] {
+		&mut self.0
+	}
+}
+
+impl From<[u8; 32]> for AccountId32 {
+	fn from(x: [u8; 32]) -> AccountId32 {
+		AccountId32(x)
+	}
+}
+
+impl<'a> rstd::convert::TryFrom<&'a [u8]> for AccountId32 {
+	type Error = ();
+	fn try_from(x: &'a [u8]) -> Result<AccountId32, ()> {
+		if x.len() == 32 {
+			let mut r = AccountId32::default();
+			r.0.copy_from_slice(x);
+			Ok(r)
+		} else {
+			Err(())
+		}
+	}
+}
+
+impl From<AccountId32> for [u8; 32] {
+	fn from(x: AccountId32) -> [u8; 32] {
+		x.0
+	}
+}
+
+#[cfg(feature = "std")]
+impl std::fmt::Display for AccountId32 {
+	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+		write!(f, "{}", self.to_ss58check())
+	}
+}
+
+impl rstd::fmt::Debug for AccountId32 {
+	#[cfg(feature = "std")]
+	fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
+		let s = self.to_ss58check();
+		write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
+	}
+
+	#[cfg(not(feature = "std"))]
+	fn fmt(&self, _: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
+		Ok(())
+	}
+}
+
+#[cfg(feature = "std")]
+impl serde::Serialize for AccountId32 {
+	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
+		serializer.serialize_str(&self.to_ss58check())
+	}
+}
+
+#[cfg(feature = "std")]
+impl<'de> serde::Deserialize<'de> for AccountId32 {
+	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
+		Ss58Codec::from_ss58check(&String::deserialize(deserializer)?)
+			.map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
+	}
+}
+
 #[cfg(feature = "std")]
 pub use self::dummy::*;
 
@@ -544,17 +647,10 @@ mod dummy {
 			Ok(Default::default())
 		}
 		fn derive<
-			Iter: Iterator<Item=DeriveJunction>
-		>(&self, _: Iter) -> Result<Self, Self::DeriveError> { Ok(Self) }
+			Iter: Iterator<Item=DeriveJunction>,
+		>(&self, _: Iter, _: Option<Dummy>) -> Result<(Self, Option<Dummy>), Self::DeriveError> { Ok((Self, None)) }
 		fn from_seed(_: &Self::Seed) -> Self { Self }
 		fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> { Ok(Self) }
-		fn from_standard_components<
-			I: Iterator<Item=DeriveJunction>
-		>(
-			_: &str,
-			_: Option<&str>,
-			_: I
-		) -> Result<Self, SecretStringError> { Ok(Self) }
 		fn sign(&self, _: &[u8]) -> Self::Signature { Self }
 		fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
 		fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true }
@@ -604,7 +700,10 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
 	fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError>;
 
 	/// Derive a child key from a series of given junctions.
-	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Result<Self, Self::DeriveError>;
+	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
+		path: Iter,
+		seed: Option<Self::Seed>,
+	) -> Result<(Self, Option<Self::Seed>), Self::DeriveError>;
 
 	/// Generate new key pair from the provided `seed`.
 	///
@@ -619,11 +718,6 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
 	/// by an attacker then they can also derive your key.
 	fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError>;
 
-	/// Construct a key from a phrase, password and path.
-	fn from_standard_components<
-		I: Iterator<Item=DeriveJunction>
-	>(phrase: &str, password: Option<&str>, path: I) -> Result<Self, SecretStringError>;
-
 	/// Sign a message.
 	fn sign(&self, message: &[u8]) -> Self::Signature;
 
@@ -636,7 +730,9 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
 	/// Get the public key.
 	fn public(&self) -> Self::Public;
 
-	/// Interprets the string `s` in order to generate a key Pair.
+	/// Interprets the string `s` in order to generate a key Pair. Returns both the pair and an optional seed, in the
+	/// case that the pair can be expressed as a direct derivation from a seed (some cases, such as Sr25519 derivations
+	/// with path components, cannot).
 	///
 	/// This takes a helper function to do the key generation from a phrase, password and
 	/// junction iterator.
@@ -662,31 +758,40 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
 	/// be equivalent to no password at all.
 	///
 	/// `None` is returned if no matches are found.
-	fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
-		let hex_seed = if s.starts_with("0x") {
-			&s[2..]
-		} else {
-			s
-		};
-
-		if let Ok(d) = hex::decode(hex_seed) {
-			if let Ok(r) = Self::from_seed_slice(&d) {
-				return Ok(r)
-			}
-		}
-
-		let re = Regex::new(r"^(?P<phrase>\w+( \w+)*)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
+	fn from_string_with_seed(s: &str, password_override: Option<&str>) -> Result<(Self, Option<Self::Seed>), SecretStringError> {
+		let re = Regex::new(r"^(?P<phrase>[\d\w ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
 			.expect("constructed from known-good static value; qed");
 		let cap = re.captures(s).ok_or(SecretStringError::InvalidFormat)?;
+
 		let re_junction = Regex::new(r"/(/?[^/]+)")
 			.expect("constructed from known-good static value; qed");
 		let path = re_junction.captures_iter(&cap["path"])
 			.map(|f| DeriveJunction::from(&f[1]));
-		Self::from_standard_components(
-			cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE),
-			password_override.or_else(|| cap.name("password").map(|m| m.as_str())),
-			path,
-		)
+
+		let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE);
+		let password = password_override.or_else(|| cap.name("password").map(|m| m.as_str()));
+
+		let (root, seed) = if phrase.starts_with("0x") {
+			hex::decode(&phrase[2..]).ok()
+				.and_then(|seed_vec| {
+					let mut seed = Self::Seed::default();
+					if seed.as_ref().len() == seed_vec.len() {
+						seed.as_mut().copy_from_slice(&seed_vec);
+						Some((Self::from_seed(&seed), seed))
+					} else {
+						None
+					}
+				})
+				.ok_or(SecretStringError::InvalidSeed)?
+		} else {
+			Self::from_phrase(phrase, password)
+				.map_err(|_| SecretStringError::InvalidPhrase)?
+		};
+		root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath)
+	}
+
+	fn from_string(s: &str, password_override: Option<&str>) -> Result<Self, SecretStringError> {
+		Self::from_string_with_seed(s, password_override).map(|x| x.0)
 	}
 
 	/// Return a vec filled with raw data.
@@ -846,13 +951,13 @@ mod tests {
 	}
 	impl Pair for TestPair {
 		type Public = TestPublic;
-		type Seed = [u8; 0];
+		type Seed = [u8; 8];
 		type Signature = [u8; 0];
 		type DeriveError = ();
 
-		fn generate() -> (Self, <Self as Pair>::Seed) { (TestPair::Generated, []) }
+		fn generate() -> (Self, <Self as Pair>::Seed) { (TestPair::Generated, [0u8; 8]) }
 		fn generate_with_phrase(_password: Option<&str>) -> (Self, String, <Self as Pair>::Seed) {
-			(TestPair::GeneratedWithPhrase, "".into(), [])
+			(TestPair::GeneratedWithPhrase, "".into(), [0u8; 8])
 		}
 		fn from_phrase(phrase: &str, password: Option<&str>)
 			-> Result<(Self, <Self as Pair>::Seed), SecretStringError>
@@ -860,14 +965,20 @@ mod tests {
 			Ok((TestPair::GeneratedFromPhrase {
 				phrase: phrase.to_owned(),
 				password: password.map(Into::into)
-			}, []))
+			}, [0u8; 8]))
 		}
-		fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter)
-			-> Result<Self, Self::DeriveError>
+		fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path_iter: Iter, _: Option<[u8; 8]>)
+			-> Result<(Self, Option<[u8; 8]>), Self::DeriveError>
 		{
-			Err(())
+			Ok((match self.clone() {
+				TestPair::Standard {phrase, password, path} =>
+					TestPair::Standard { phrase, password, path: path.into_iter().chain(path_iter).collect() },
+				TestPair::GeneratedFromPhrase {phrase, password} =>
+					TestPair::Standard { phrase, password, path: path_iter.collect() },
+				x => if path_iter.count() == 0 { x } else { return Err(()) },
+			}, None))
 		}
-		fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(vec![]) }
+		fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(_seed.as_ref().to_owned()) }
 		fn sign(&self, _message: &[u8]) -> Self::Signature { [] }
 		fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
 		fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(
@@ -876,17 +987,6 @@ mod tests {
 			_pubkey: P
 		) -> bool { true }
 		fn public(&self) -> Self::Public { TestPublic }
-		fn from_standard_components<I: Iterator<Item=DeriveJunction>>(
-			phrase: &str,
-			password: Option<&str>,
-			path: I
-		) -> Result<Self, SecretStringError> {
-			Ok(TestPair::Standard {
-				phrase: phrase.to_owned(),
-				password: password.map(ToOwned::to_owned),
-				path: path.collect()
-			})
-		}
 		fn from_seed_slice(seed: &[u8])
 			-> Result<Self, SecretStringError>
 		{
@@ -903,10 +1003,6 @@ mod tests {
 			TestPair::from_string("0x0123456789abcdef", None),
 			Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned()))
 		);
-		assert_eq!(
-			TestPair::from_string("0123456789abcdef", None),
-			Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned()))
-		);
 	}
 
 	#[test]
diff --git a/substrate/core/primitives/src/ecdsa.rs b/substrate/core/primitives/src/ecdsa.rs
new file mode 100644
index 00000000000..abff460c910
--- /dev/null
+++ b/substrate/core/primitives/src/ecdsa.rs
@@ -0,0 +1,608 @@
+// Copyright 2017-2019 Parity Technologies (UK) Ltd.
+// This file is part of Substrate.
+
+// Substrate is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Substrate is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
+
+// tag::description[]
+//! Simple ECDSA API.
+// end::description[]
+
+use rstd::cmp::Ordering;
+use codec::{Encode, Decode};
+
+#[cfg(feature = "std")]
+use std::convert::{TryFrom, TryInto};
+#[cfg(feature = "std")]
+use substrate_bip39::seed_from_entropy;
+#[cfg(feature = "std")]
+use bip39::{Mnemonic, Language, MnemonicType};
+#[cfg(feature = "std")]
+use crate::{hashing::blake2_256, crypto::{Pair as TraitPair, DeriveJunction, SecretStringError, Ss58Codec}};
+#[cfg(feature = "std")]
+use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
+use crate::crypto::{Public as TraitPublic, UncheckedFrom, CryptoType, Derive};
+#[cfg(feature = "std")]
+use secp256k1::{PublicKey, SecretKey};
+
+/// A secret seed (which is bytewise essentially equivalent to a SecretKey).
+///
+/// We need it as a different type because `Seed` is expected to be AsRef<[u8]>.
+#[cfg(feature = "std")]
+type Seed = [u8; 32];
+
+/// The ECDSA 33-byte compressed public key.
+#[derive(Clone, Encode, Decode)]
+pub struct Public(pub [u8; 33]);
+
+impl PartialOrd for Public {
+	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+		Some(self.cmp(other))
+	}
+}
+
+impl Ord for Public {
+	fn cmp(&self, other: &Self) -> Ordering {
+		self.0[..].cmp(&other.0[..])
+	}
+}
+
+impl PartialEq for Public {
+	fn eq(&self, other: &Self) -> bool {
+		&self.0[..] == &other.0[..]
+	}
+}
+
+impl Eq for Public {}
+
+impl Default for Public {
+	fn default() -> Self {
+		Public([0u8; 33])
+	}
+}
+
+/// A key pair.
+#[cfg(feature = "std")]
+#[derive(Clone)]
+pub struct Pair {
+	public: PublicKey,
+	secret: SecretKey,
+}
+
+impl AsRef<[u8; 33]> for Public {
+	fn as_ref(&self) -> &[u8; 33] {
+		&self.0
+	}
+}
+
+impl AsRef<[u8]> for Public {
+	fn as_ref(&self) -> &[u8] {
+		&self.0[..]
+	}
+}
+
+impl AsMut<[u8]> for Public {
+	fn as_mut(&mut self) -> &mut [u8] {
+		&mut self.0[..]
+	}
+}
+
+impl rstd::convert::TryFrom<&[u8]> for Public {
+	type Error = ();
+
+	fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
+		if data.len() == 33 {
+			let mut inner = [0u8; 33];
+			inner.copy_from_slice(data);
+			Ok(Public(inner))
+		} else {
+			Err(())
+		}
+	}
+}
+
+impl From<Public> for [u8; 33] {
+	fn from(x: Public) -> Self {
+		x.0
+	}
+}
+
+#[cfg(feature = "std")]
+impl From<Pair> for Public {
+	fn from(x: Pair) -> Self {
+		x.public()
+	}
+}
+
+impl UncheckedFrom<[u8; 33]> for Public {
+	fn unchecked_from(x: [u8; 33]) -> Self {
+		Public(x)
+	}
+}
+
+#[cfg(feature = "std")]
+impl std::fmt::Display for Public {
+	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+		write!(f, "{}", self.to_ss58check())
+	}
+}
+
+#[cfg(feature = "std")]
+impl std::fmt::Debug for Public {
+	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+		let s = self.to_ss58check();
+		write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&&self.0[..]), &s[0..8])
+	}
+}
+
+#[cfg(feature = "std")]
+impl Serialize for Public {
+	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+		serializer.serialize_str(&self.to_ss58check())
+	}
+}
+
+#[cfg(feature = "std")]
+impl<'de> Deserialize<'de> for Public {
+	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
+		Public::from_ss58check(&String::deserialize(deserializer)?)
+			.map_err(|e| de::Error::custom(format!("{:?}", e)))
+	}
+}
+
+#[cfg(feature = "std")]
+impl std::hash::Hash for Public {
+	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+		self.0.hash(state);
+	}
+}
+
+/// A signature (a 512-bit value).
+#[derive(Encode, Decode)]
+pub struct Signature([u8; 65]);
+
+impl rstd::convert::TryFrom<&[u8]> for Signature {
+	type Error = ();
+
+	fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
+		if data.len() == 65 {
+			let mut inner = [0u8; 65];
+			inner.copy_from_slice(data);
+			Ok(Signature(inner))
+		} else {
+			Err(())
+		}
+	}
+}
+
+impl Clone for Signature {
+	fn clone(&self) -> Self {
+		let mut r = [0u8; 65];
+		r.copy_from_slice(&self.0[..]);
+		Signature(r)
+	}
+}
+
+impl Default for Signature {
+	fn default() -> Self {
+		Signature([0u8; 65])
+	}
+}
+
+impl PartialEq for Signature {
+	fn eq(&self, b: &Self) -> bool {
+		self.0[..] == b.0[..]
+	}
+}
+
+impl Eq for Signature {}
+
+impl From<Signature> for [u8; 65] {
+	fn from(v: Signature) -> [u8; 65] {
+		v.0
+	}
+}
+
+impl AsRef<[u8; 65]> for Signature {
+	fn as_ref(&self) -> &[u8; 65] {
+		&self.0
+	}
+}
+
+impl AsRef<[u8]> for Signature {
+	fn as_ref(&self) -> &[u8] {
+		&self.0[..]
+	}
+}
+
+impl AsMut<[u8]> for Signature {
+	fn as_mut(&mut self) -> &mut [u8] {
+		&mut self.0[..]
+	}
+}
+
+#[cfg(feature = "std")]
+impl std::fmt::Debug for Signature {
+	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+		write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
+	}
+}
+
+#[cfg(feature = "std")]
+impl std::hash::Hash for Signature {
+	fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+		std::hash::Hash::hash(&self.0[..], state);
+	}
+}
+
+impl Signature {
+	/// A new instance from the given 65-byte `data`.
+	///
+	/// NOTE: No checking goes on to ensure this is a real signature. Only use it if
+	/// you are certain that the array actually is a signature. GIGO!
+	pub fn from_raw(data: [u8; 65]) -> Signature {
+		Signature(data)
+	}
+
+	/// Recover the public key from this signature and a message.
+	#[cfg(feature = "std")]
+	pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
+		let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
+		let sig: (_, _) = self.try_into().ok()?;
+		secp256k1::recover(&message, &sig.0, &sig.1).ok()
+			.map(|recovered| Public(recovered.serialize_compressed()))
+	}
+}
+
+#[cfg(feature = "std")]
+impl From<(secp256k1::Signature, secp256k1::RecoveryId)> for Signature {
+	fn from(x: (secp256k1::Signature, secp256k1::RecoveryId)) -> Signature {
+		let mut r = Self::default();
+		r.0[0..64].copy_from_slice(&x.0.serialize()[..]);
+		r.0[64] = x.1.serialize();
+		r
+	}
+}
+
+#[cfg(feature = "std")]
+impl<'a> TryFrom<&'a Signature> for (secp256k1::Signature, secp256k1::RecoveryId) {
+	type Error = ();
+	fn try_from(x: &'a Signature) -> Result<(secp256k1::Signature, secp256k1::RecoveryId), Self::Error> {
+		Ok((
+			secp256k1::Signature::parse_slice(&x.0[0..64]).expect("hardcoded to 64 bytes; qed"),
+			secp256k1::RecoveryId::parse(x.0[64]).map_err(|_| ())?,
+		))
+	}
+}
+
+/// An error type for SS58 decoding.
+#[cfg(feature = "std")]
+#[derive(Clone, Copy, Eq, PartialEq, Debug)]
+pub enum PublicError {
+	/// Bad alphabet.
+	BadBase58,
+	/// Bad length.
+	BadLength,
+	/// Unknown version.
+	UnknownVersion,
+	/// Invalid checksum.
+	InvalidChecksum,
+}
+
+impl Public {
+	/// A new instance from the given 33-byte `data`.
+	///
+	/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
+	/// you are certain that the array actually is a pubkey. GIGO!
+	pub fn from_raw(data: [u8; 33]) -> Self {
+		Public(data)
+	}
+
+	/// Return a slice filled with raw data.
+	pub fn as_array_ref(&self) -> &[u8; 33] {
+		self.as_ref()
+	}
+}
+
+impl TraitPublic for Public {
+	/// A new instance from the given slice that should be 33 bytes long.
+	///
+	/// NOTE: No checking goes on to ensure this is a real public key. Only use it if
+	/// you are certain that the array actually is a pubkey. GIGO!
+	fn from_slice(data: &[u8]) -> Self {
+		let mut r = [0u8; 33];
+		r.copy_from_slice(data);
+		Public(r)
+	}
+}
+
+impl Derive for Public {}
+
+/// Derive a single hard junction.
+#[cfg(feature = "std")]
+fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
+	("Secp256k1HDKD", secret_seed, cc).using_encoded(|data| {
+		let mut res = [0u8; 32];
+		res.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes());
+		res
+	})
+}
+
+/// An error when deriving a key.
+#[cfg(feature = "std")]
+pub enum DeriveError {
+	/// A soft key was found in the path (and is unsupported).
+	SoftKeyInPath,
+}
+
+#[cfg(feature = "std")]
+impl TraitPair for Pair {
+	type Public = Public;
+	type Seed = Seed;
+	type Signature = Signature;
+	type DeriveError = DeriveError;
+
+	/// Generate new secure (random) key pair and provide the recovery phrase.
+	///
+	/// You can recover the same key later with `from_phrase`.
+	fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) {
+		let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
+		let phrase = mnemonic.phrase();
+		let (pair, seed) = Self::from_phrase(phrase, password)
+			.expect("All phrases generated by Mnemonic are valid; qed");
+		(
+			pair,
+			phrase.to_owned(),
+			seed,
+		)
+	}
+
+	/// Generate key pair from given recovery phrase and password.
+	fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
+		let big_seed = seed_from_entropy(
+			Mnemonic::from_phrase(phrase, Language::English)
+				.map_err(|_| SecretStringError::InvalidPhrase)?.entropy(),
+			password.unwrap_or(""),
+		).map_err(|_| SecretStringError::InvalidSeed)?;
+		let mut seed = Seed::default();
+		seed.copy_from_slice(&big_seed[0..32]);
+		Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed))
+	}
+
+	/// Make a new key pair from secret seed material.
+	///
+	/// You should never need to use this; generate(), generate_with_phrase
+	fn from_seed(seed: &Seed) -> Pair {
+		Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed")
+	}
+
+	/// Make a new key pair from secret seed material. The slice must be 32 bytes long or it
+	/// will return `None`.
+	///
+	/// You should never need to use this; generate(), generate_with_phrase
+	fn from_seed_slice(seed_slice: &[u8]) -> Result<Pair, SecretStringError> {
+		let secret = SecretKey::parse_slice(seed_slice)
+			.map_err(|_| SecretStringError::InvalidSeedLength)?;
+		let public = PublicKey::from_secret_key(&secret);
+		Ok(Pair{ secret, public })
+	}
+
+	/// Derive a child key from a series of given junctions.
+	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
+		path: Iter,
+		_seed: Option<Seed>
+	) -> Result<(Pair, Option<Seed>), DeriveError> {
+		let mut acc = self.secret.serialize();
+		for j in path {
+			match j {
+				DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath),
+				DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc),
+			}
+		}
+		Ok((Self::from_seed(&acc), Some(acc)))
+	}
+
+	/// Get the public key.
+	fn public(&self) -> Public {
+		Public(self.public.serialize_compressed())
+	}
+
+	/// Sign a message.
+	fn sign(&self, message: &[u8]) -> Signature {
+		let message = secp256k1::Message::parse(&blake2_256(message));
+		secp256k1::sign(&message, &self.secret).into()
+	}
+
+	/// Verify a signature on a message. Returns true if the signature is good.
+	fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
+		let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
+		let sig: (_, _) = match sig.try_into() { Ok(x) => x, _ => return false };
+		match secp256k1::recover(&message, &sig.0, &sig.1) {
+			Ok(actual) => &pubkey.0[..] == &actual.serialize_compressed()[..],
+			_ => false,
+		}
+	}
+
+	/// Verify a signature on a message. Returns true if the signature is good.
+	///
+	/// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct
+	/// size. Use it only if you're coming from byte buffers and need the speed.
+	fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
+		let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
+		if sig.len() != 65 { return false }
+		let ri = match secp256k1::RecoveryId::parse(sig[64]) { Ok(x) => x, _ => return false };
+		let sig = match secp256k1::Signature::parse_slice(&sig[0..64]) { Ok(x) => x, _ => return false };
+		match secp256k1::recover(&message, &sig, &ri) {
+			Ok(actual) => pubkey.as_ref() == &actual.serialize_compressed()[..],
+			_ => false,
+		}
+	}
+
+	/// Return a vec filled with raw data.
+	fn to_raw_vec(&self) -> Vec<u8> {
+		self.seed().to_vec()
+	}
+}
+
+#[cfg(feature = "std")]
+impl Pair {
+	/// Get the seed for this key.
+	pub fn seed(&self) -> Seed {
+		self.secret.serialize()
+	}
+
+	/// Exactly as `from_string` except that if no matches are found then, the the first 32
+	/// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey.
+	pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair {
+		Self::from_string(s, password_override).unwrap_or_else(|_| {
+			let mut padded_seed: Seed = [' ' as u8; 32];
+			let len = s.len().min(32);
+			padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]);
+			Self::from_seed(&padded_seed)
+		})
+	}
+}
+
+impl CryptoType for Public {
+	#[cfg(feature="std")]
+	type Pair = Pair;
+}
+
+impl CryptoType for Signature {
+	#[cfg(feature="std")]
+	type Pair = Pair;
+}
+
+#[cfg(feature = "std")]
+impl CryptoType for Pair {
+	type Pair = Pair;
+}
+
+#[cfg(test)]
+mod test {
+	use super::*;
+	use hex_literal::hex;
+	use crate::crypto::DEV_PHRASE;
+
+	#[test]
+	fn default_phrase_should_be_used() {
+		assert_eq!(
+			Pair::from_string("//Alice///password", None).unwrap().public(),
+			Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
+		);
+	}
+
+	#[test]
+	fn seed_and_derive_should_work() {
+		let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60");
+		let pair = Pair::from_seed(&seed);
+		assert_eq!(pair.seed(), seed);
+		let path = vec![DeriveJunction::Hard([0u8; 32])];
+		let derived = pair.derive(path.into_iter(), None).ok().unwrap();
+		assert_eq!(
+			derived.0.seed(),
+			hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61")
+		);
+	}
+
+	#[test]
+	fn test_vector_should_work() {
+		let pair = Pair::from_seed(
+			&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
+		);
+		let public = pair.public();
+		assert_eq!(public, Public::from_raw(
+			hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")
+		));
+		let message = b"";
+		let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00");
+		let signature = Signature::from_raw(signature);
+		assert!(&pair.sign(&message[..]) == &signature);
+		assert!(Pair::verify(&signature, &message[..], &public));
+	}
+
+	#[test]
+	fn test_vector_by_string_should_work() {
+		let pair = Pair::from_string(
+			"0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
+			None
+		).unwrap();
+		let public = pair.public();
+		assert_eq!(public, Public::from_raw(
+			hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")
+		));
+		let message = b"";
+		let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00");
+		let signature = Signature::from_raw(signature);
+		assert!(&pair.sign(&message[..]) == &signature);
+		assert!(Pair::verify(&signature, &message[..], &public));
+	}
+
+	#[test]
+	fn generated_pair_should_work() {
+		let (pair, _) = Pair::generate();
+		let public = pair.public();
+		let message = b"Something important";
+		let signature = pair.sign(&message[..]);
+		assert!(Pair::verify(&signature, &message[..], &public));
+		assert!(!Pair::verify(&signature, b"Something else", &public));
+	}
+
+	#[test]
+	fn seeded_pair_should_work() {
+		let pair = Pair::from_seed(b"12345678901234567890123456789012");
+		let public = pair.public();
+		assert_eq!(public, Public::from_raw(
+			hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9")
+		));
+		let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
+		let signature = pair.sign(&message[..]);
+		println!("Correct signature: {:?}", signature);
+		assert!(Pair::verify(&signature, &message[..], &public));
+		assert!(!Pair::verify(&signature, "Other message", &public));
+	}
+
+	#[test]
+	fn generate_with_phrase_recovery_possible() {
+		let (pair1, phrase, _) = Pair::generate_with_phrase(None);
+		let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
+
+		assert_eq!(pair1.public(), pair2.public());
+	}
+
+	#[test]
+	fn generate_with_password_phrase_recovery_possible() {
+		let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
+		let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap();
+
+		assert_eq!(pair1.public(), pair2.public());
+	}
+
+	#[test]
+	fn password_does_something() {
+		let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
+		let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
+
+		assert_ne!(pair1.public(), pair2.public());
+	}
+
+	#[test]
+	fn ss58check_roundtrip_works() {
+		let pair = Pair::from_seed(b"12345678901234567890123456789012");
+		let public = pair.public();
+		let s = public.to_ss58check();
+		println!("Correct: {}", s);
+		let cmp = Public::from_ss58check(&s).unwrap();
+		assert_eq!(cmp, public);
+	}
+}
diff --git a/substrate/core/primitives/src/ed25519.rs b/substrate/core/primitives/src/ed25519.rs
index ff3b21e160d..8c3aa9f89db 100644
--- a/substrate/core/primitives/src/ed25519.rs
+++ b/substrate/core/primitives/src/ed25519.rs
@@ -406,7 +406,10 @@ impl TraitPair for Pair {
 	}
 
 	/// Derive a child key from a series of given junctions.
-	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Result<Pair, DeriveError> {
+	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
+		path: Iter,
+		_seed: Option<Seed>,
+	) -> Result<(Pair, Option<Seed>), DeriveError> {
 		let mut acc = self.0.secret.to_bytes();
 		for j in path {
 			match j {
@@ -414,18 +417,7 @@ impl TraitPair for Pair {
 				DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc),
 			}
 		}
-		Ok(Self::from_seed(&acc))
-	}
-
-	/// Generate a key from the phrase, password and derivation path.
-	fn from_standard_components<I: Iterator<Item=DeriveJunction>>(
-		phrase: &str,
-		password: Option<&str>,
-		path: I
-	) -> Result<Pair, SecretStringError> {
-		Self::from_phrase(phrase, password)?.0
-			.derive(path)
-			.map_err(|_| SecretStringError::InvalidPath)
+		Ok((Self::from_seed(&acc), Some(acc)))
 	}
 
 	/// Get the public key.
@@ -528,7 +520,7 @@ mod test {
 		let pair = Pair::from_seed(&seed);
 		assert_eq!(pair.seed(), &seed);
 		let path = vec![DeriveJunction::Hard([0u8; 32])];
-		let derived = pair.derive(path.into_iter()).ok().unwrap();
+		let derived = pair.derive(path.into_iter(), None).ok().unwrap().0;
 		assert_eq!(
 			derived.seed(),
 			&hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c")
diff --git a/substrate/core/primitives/src/hexdisplay.rs b/substrate/core/primitives/src/hexdisplay.rs
index 6765ce517ea..2c8533e25b5 100644
--- a/substrate/core/primitives/src/hexdisplay.rs
+++ b/substrate/core/primitives/src/hexdisplay.rs
@@ -80,7 +80,7 @@ macro_rules! impl_non_endians {
 
 impl_non_endians!([u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8],
 	[u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40],
-	[u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128]);
+	[u8; 48], [u8; 56], [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128]);
 
 /// Format into ASCII + # + hex, suitable for storage key preimages.
 pub fn ascii_format(asciish: &[u8]) -> String {
diff --git a/substrate/core/primitives/src/lib.rs b/substrate/core/primitives/src/lib.rs
index 48d3d998fa8..d1b42766a08 100644
--- a/substrate/core/primitives/src/lib.rs
+++ b/substrate/core/primitives/src/lib.rs
@@ -59,6 +59,7 @@ pub mod u32_trait;
 
 pub mod ed25519;
 pub mod sr25519;
+pub mod ecdsa;
 pub mod hash;
 mod hasher;
 pub mod offchain;
diff --git a/substrate/core/primitives/src/sr25519.rs b/substrate/core/primitives/src/sr25519.rs
index f2160b88b74..bb319b82218 100644
--- a/substrate/core/primitives/src/sr25519.rs
+++ b/substrate/core/primitives/src/sr25519.rs
@@ -388,8 +388,8 @@ impl AsRef<schnorrkel::Keypair> for Pair {
 
 /// Derive a single hard junction.
 #[cfg(feature = "std")]
-fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> SecretKey {
-	secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0.expand(ExpansionMode::Ed25519)
+fn derive_hard_junction(secret: &SecretKey, cc: &[u8; CHAIN_CODE_LENGTH]) -> MiniSecretKey {
+	secret.hard_derive_mini_secret_key(Some(ChainCode(cc.clone())), b"").0
 }
 
 /// The raw secret seed, which can be used to recreate the `Pair`.
@@ -444,17 +444,6 @@ impl TraitPair for Pair {
 		}
 	}
 
-	/// Generate a key from the phrase, password and derivation path.
-	fn from_standard_components<I: Iterator<Item=DeriveJunction>>(
-		phrase: &str,
-		password: Option<&str>,
-		path: I
-	) -> Result<Pair, SecretStringError> {
-		Self::from_phrase(phrase, password)?.0
-			.derive(path)
-			.map_err(|_| SecretStringError::InvalidPath)
-	}
-
 	fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) {
 		let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
 		let phrase = mnemonic.phrase();
@@ -473,13 +462,27 @@ impl TraitPair for Pair {
 			.map(|m| Self::from_entropy(m.entropy(), password))
 	}
 
-	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Result<Pair, Self::DeriveError> {
+	fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
+		path: Iter,
+		seed: Option<Seed>,
+	) -> Result<(Pair, Option<Seed>), Self::DeriveError> {
+		let seed = if let Some(s) = seed {
+			if let Ok(msk) = MiniSecretKey::from_bytes(&s) {
+				if msk.expand(ExpansionMode::Ed25519) == self.0.secret {
+					Some(msk)
+				} else { None }
+			} else { None }
+		} else { None };
 		let init = self.0.secret.clone();
-		let result = path.fold(init, |acc, j| match j {
-			DeriveJunction::Soft(cc) => acc.derived_key_simple(ChainCode(cc), &[]).0,
-			DeriveJunction::Hard(cc) => derive_hard_junction(&acc, &cc),
+		let (result, seed) = path.fold((init, seed), |(acc, acc_seed), j| match (j, acc_seed) {
+			(DeriveJunction::Soft(cc), _) =>
+				(acc.derived_key_simple(ChainCode(cc), &[]).0, None),
+			(DeriveJunction::Hard(cc), maybe_seed) => {
+				let seed = derive_hard_junction(&acc, &cc);
+				(seed.expand(ExpansionMode::Ed25519), maybe_seed.map(|_| seed))
+			}
 		});
-		Ok(Self(result.into()))
+		Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s))))
 	}
 
 	fn sign(&self, message: &[u8]) -> Signature {
@@ -621,9 +624,9 @@ mod test {
 		let pair = Pair::from_seed(&hex!(
 			"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
 		));
-		let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap();
-		let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter()).unwrap();
-		let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter()).unwrap();
+		let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0;
+		let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0;
+		let derive_2 = pair.derive(Some(DeriveJunction::soft(2)).into_iter(), None).unwrap().0;
 		assert_eq!(derive_1.public(), derive_1b.public());
 		assert_ne!(derive_1.public(), derive_2.public());
 	}
@@ -633,9 +636,9 @@ mod test {
 		let pair = Pair::from_seed(&hex!(
 			"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
 		));
-		let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap();
-		let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter()).unwrap();
-		let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter()).unwrap();
+		let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0;
+		let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0;
+		let derive_2 = pair.derive(Some(DeriveJunction::hard(2)).into_iter(), None).unwrap().0;
 		assert_eq!(derive_1.public(), derive_1b.public());
 		assert_ne!(derive_1.public(), derive_2.public());
 	}
@@ -646,7 +649,7 @@ mod test {
 			"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
 		));
 		let path = Some(DeriveJunction::soft(1));
-		let pair_1 = pair.derive(path.clone().into_iter()).unwrap();
+		let pair_1 = pair.derive(path.clone().into_iter(), None).unwrap().0;
 		let public_1 = pair.public().derive(path.into_iter()).unwrap();
 		assert_eq!(pair_1.public(), public_1);
 	}
diff --git a/substrate/core/sr-io/src/lib.rs b/substrate/core/sr-io/src/lib.rs
index b0274286dc2..fe5e50b3eda 100644
--- a/substrate/core/sr-io/src/lib.rs
+++ b/substrate/core/sr-io/src/lib.rs
@@ -220,15 +220,20 @@ export_api! {
 
 		/// Verify and recover a SECP256k1 ECDSA signature.
 		/// - `sig` is passed in RSV format. V should be either 0/1 or 27/28.
-		/// - returns `Err` if the signature is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix).
+		/// - returns `Err` if the signature is bad, otherwise the 64-byte raw pubkey (doesn't include the 0x04 prefix).
 		fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError>;
+
+		/// Verify and recover a SECP256k1 ECDSA signature.
+		/// - `sig` is passed in RSV format. V should be either 0/1 or 27/28.
+		/// - returns `Err` if the signature is bad, otherwise the 33-byte compressed pubkey.
+		fn secp256k1_ecdsa_recover_compressed(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 33], EcdsaVerifyError>;
 	}
 }
 
 export_api! {
 	pub(crate) trait HashingApi {
 		/// Conduct a 256-bit Keccak hash.
-		fn keccak_256(data: &[u8]) -> [u8; 32] ;
+		fn keccak_256(data: &[u8]) -> [u8; 32];
 
 		/// Conduct a 128-bit Blake2 hash.
 		fn blake2_128(data: &[u8]) -> [u8; 16];
diff --git a/substrate/core/sr-io/with_std.rs b/substrate/core/sr-io/with_std.rs
index de40115cbe7..fdd32124c12 100644
--- a/substrate/core/sr-io/with_std.rs
+++ b/substrate/core/sr-io/with_std.rs
@@ -300,6 +300,16 @@ impl CryptoApi for () {
 		res.copy_from_slice(&pubkey.serialize()[1..65]);
 		Ok(res)
 	}
+
+	fn secp256k1_ecdsa_recover_compressed(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 33], EcdsaVerifyError> {
+		let rs = secp256k1::Signature::parse_slice(&sig[0..64])
+			.map_err(|_| EcdsaVerifyError::BadRS)?;
+		let v = secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8)
+			.map_err(|_| EcdsaVerifyError::BadV)?;
+		let pubkey = secp256k1::recover(&secp256k1::Message::parse(msg), &rs, &v)
+			.map_err(|_| EcdsaVerifyError::BadSignature)?;
+		Ok(pubkey.serialize_compressed())
+	}
 }
 
 impl HashingApi for () {
diff --git a/substrate/core/sr-io/without_std.rs b/substrate/core/sr-io/without_std.rs
index 789098185e0..c3f7d62031b 100644
--- a/substrate/core/sr-io/without_std.rs
+++ b/substrate/core/sr-io/without_std.rs
@@ -394,12 +394,23 @@ pub mod ext {
 		) -> u32;
 
 		/// Note: ext_secp256k1_ecdsa_recover returns 0 if the signature is correct, nonzero otherwise.
+		///
+		/// pubkey_data must point to 64 bytes.
 		fn ext_secp256k1_ecdsa_recover(
 			msg_data: *const u8,
 			sig_data: *const u8,
 			pubkey_data: *mut u8,
 		) -> u32;
 
+		/// Note: ext_secp256k1_ecdsa_recover_compressed returns 0 if the signature is correct, nonzero otherwise.
+		///
+		/// pubkey_data must point to 33 bytes.
+		fn ext_secp256k1_ecdsa_recover_compressed(
+			msg_data: *const u8,
+			sig_data: *const u8,
+			pubkey_data: *mut u8,
+		) -> u32;
+
 		//================================
 		// Offchain-worker Context
 		//================================
@@ -971,6 +982,19 @@ impl CryptoApi for () {
 			_ => unreachable!("`ext_secp256k1_ecdsa_recover` only returns 0, 1, 2 or 3; qed"),
 		}
 	}
+
+	fn secp256k1_ecdsa_recover_compressed(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 33], EcdsaVerifyError> {
+		let mut pubkey = [0u8; 33];
+		match unsafe {
+			ext_secp256k1_ecdsa_recover_compressed.get()(msg.as_ptr(), sig.as_ptr(), pubkey.as_mut_ptr())
+		} {
+			0 => Ok(pubkey),
+			1 => Err(EcdsaVerifyError::BadRS),
+			2 => Err(EcdsaVerifyError::BadV),
+			3 => Err(EcdsaVerifyError::BadSignature),
+			_ => unreachable!("`ext_secp256k1_ecdsa_recover_compressed` only returns 0, 1, 2 or 3; qed"),
+		}
+	}
 }
 
 impl OffchainApi for () {
diff --git a/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs
index d50314f33bf..4af8d9a95b9 100644
--- a/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs
+++ b/substrate/core/sr-primitives/src/generic/unchecked_extrinsic.rs
@@ -21,7 +21,7 @@ use rstd::fmt;
 use runtime_io::blake2_256;
 use codec::{Decode, Encode, EncodeLike, Input, Error};
 use crate::{
-	traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic},
+	traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount},
 	generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction},
 };
 
@@ -98,7 +98,8 @@ for
 where
 	Address: Member + MaybeDisplay,
 	Call: Encode + Member,
-	Signature: Member + traits::Verify<Signer=AccountId>,
+	Signature: Member + traits::Verify,
+	<Signature as traits::Verify>::Signer: IdentifyAccount<AccountId=AccountId>,
 	Extra: SignedExtension<AccountId=AccountId>,
 	AccountId: Member + MaybeDisplay,
 	Lookup: traits::Lookup<Source=Address, Target=AccountId>,
@@ -284,17 +285,26 @@ mod tests {
 	use super::*;
 	use runtime_io::blake2_256;
 	use crate::codec::{Encode, Decode};
-	use crate::traits::{SignedExtension, IdentityLookup};
+	use crate::traits::{SignedExtension, IdentifyAccount, IdentityLookup};
 	use serde::{Serialize, Deserialize};
 
 	type TestContext = IdentityLookup<u64>;
 
+	#[derive(Eq, PartialEq, Clone, Copy, Debug, Serialize, Deserialize, Encode, Decode)]
+	pub struct TestSigner(pub u64);
+	impl From<u64> for TestSigner { fn from(x: u64) -> Self { Self(x) } }
+	impl From<TestSigner> for u64 { fn from(x: TestSigner) -> Self { x.0 } }
+	impl IdentifyAccount for TestSigner {
+		type AccountId = u64;
+		fn into_account(self) -> u64 { self.into() }
+	}
+
 	#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)]
 	struct TestSig(u64, Vec<u8>);
 	impl traits::Verify for TestSig {
-		type Signer = u64;
-		fn verify<L: traits::Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
-			*signer == self.0 && msg.get() == &self.1[..]
+		type Signer = TestSigner;
+		fn verify<L: traits::Lazy<[u8]>>(&self, mut msg: L, signer: &u64) -> bool {
+			signer == &self.0 && msg.get() == &self.1[..]
 		}
 	}
 
diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs
index ea295fbea61..84f7bbcff64 100644
--- a/substrate/core/sr-primitives/src/lib.rs
+++ b/substrate/core/sr-primitives/src/lib.rs
@@ -42,7 +42,7 @@ pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
 
 use rstd::prelude::*;
 use rstd::convert::TryFrom;
-use primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
+use primitives::{crypto, ed25519, sr25519, ecdsa, hash::{H256, H512}};
 use codec::{Encode, Decode};
 
 #[cfg(feature = "std")]
@@ -59,7 +59,7 @@ pub mod weights;
 pub use generic::{DigestItem, Digest};
 
 /// Re-export this since it's part of the API of this crate.
-pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType}};
+pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType, AccountId32}};
 pub use app_crypto::RuntimeAppPublic;
 
 /// Re-export `RuntimeDebug`, to avoid dependency clutter.
@@ -117,6 +117,7 @@ macro_rules! create_runtime_str {
 
 #[cfg(feature = "std")]
 pub use serde::{Serialize, Deserialize, de::DeserializeOwned};
+use crate::traits::IdentifyAccount;
 
 /// Complex storage builder stuff.
 #[cfg(feature = "std")]
@@ -175,6 +176,8 @@ pub enum MultiSignature {
 	Ed25519(ed25519::Signature),
 	/// An Sr25519 signature.
 	Sr25519(sr25519::Signature),
+	/// An ECDSA/SECP256k1 signature.
+	Ecdsa(ecdsa::Signature),
 }
 
 impl From<ed25519::Signature> for MultiSignature {
@@ -189,6 +192,12 @@ impl From<sr25519::Signature> for MultiSignature {
 	}
 }
 
+impl From<ecdsa::Signature> for MultiSignature {
+	fn from(x: ecdsa::Signature) -> Self {
+		MultiSignature::Ecdsa(x)
+	}
+}
+
 impl Default for MultiSignature {
 	fn default() -> Self {
 		MultiSignature::Ed25519(Default::default())
@@ -203,6 +212,8 @@ pub enum MultiSigner {
 	Ed25519(ed25519::Public),
 	/// An Sr25519 identity.
 	Sr25519(sr25519::Public),
+	/// An SECP256k1/ECDSA identity (actually, the Blake2 hash of the pub key).
+	Ecdsa(ecdsa::Public),
 }
 
 impl Default for MultiSigner {
@@ -224,6 +235,18 @@ impl AsRef<[u8]> for MultiSigner {
 		match *self {
 			MultiSigner::Ed25519(ref who) => who.as_ref(),
 			MultiSigner::Sr25519(ref who) => who.as_ref(),
+			MultiSigner::Ecdsa(ref who) => who.as_ref(),
+		}
+	}
+}
+
+impl traits::IdentifyAccount for MultiSigner {
+	type AccountId = AccountId32;
+	fn into_account(self) -> AccountId32 {
+		match self {
+			MultiSigner::Ed25519(who) => <[u8; 32]>::from(who).into(),
+			MultiSigner::Sr25519(who) => <[u8; 32]>::from(who).into(),
+			MultiSigner::Ecdsa(who) => runtime_io::blake2_256(who.as_ref()).into(),
 		}
 	}
 }
@@ -240,23 +263,37 @@ impl From<sr25519::Public> for MultiSigner {
 	}
 }
 
- #[cfg(feature = "std")]
+impl From<ecdsa::Public> for MultiSigner {
+	fn from(x: ecdsa::Public) -> Self {
+		MultiSigner::Ecdsa(x)
+	}
+}
+
+#[cfg(feature = "std")]
 impl std::fmt::Display for MultiSigner {
 	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
 		match *self {
 			MultiSigner::Ed25519(ref who) => write!(fmt, "ed25519: {}", who),
 			MultiSigner::Sr25519(ref who) => write!(fmt, "sr25519: {}", who),
+			MultiSigner::Ecdsa(ref who) => write!(fmt, "ecdsa: {}", who),
 		}
 	}
 }
 
 impl Verify for MultiSignature {
 	type Signer = MultiSigner;
-	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool {
+	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId32) -> bool {
+		use primitives::crypto::Public;
 		match (self, signer) {
-			(MultiSignature::Ed25519(ref sig), &MultiSigner::Ed25519(ref who)) => sig.verify(msg, who),
-			(MultiSignature::Sr25519(ref sig), &MultiSigner::Sr25519(ref who)) => sig.verify(msg, who),
-			_ => false,
+			(MultiSignature::Ed25519(ref sig), who) => sig.verify(msg, &ed25519::Public::from_slice(who.as_ref())),
+			(MultiSignature::Sr25519(ref sig), who) => sig.verify(msg, &sr25519::Public::from_slice(who.as_ref())),
+			(MultiSignature::Ecdsa(ref sig), who) => {
+				let m = runtime_io::blake2_256(msg.get());
+				match runtime_io::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) {
+					Ok(pubkey) => &runtime_io::blake2_256(pubkey.as_ref()) == <dyn AsRef<[u8; 32]>>::as_ref(who),
+					_ => false,
+				}
+			}
 		}
 	}
 }
@@ -269,12 +306,13 @@ pub struct AnySignature(H512);
 impl Verify for AnySignature {
 	type Signer = sr25519::Public;
 	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sr25519::Public) -> bool {
+		use primitives::crypto::Public;
+		let msg = msg.get();
 		sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
-			.map(|s| runtime_io::sr25519_verify(&s, msg.get(), &signer))
+			.map(|s| s.verify(msg, signer))
 			.unwrap_or(false)
 		|| ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
-			.and_then(|s| ed25519::Public::try_from(signer.0.as_ref()).map(|p| (s, p)))
-			.map(|(s, p)| runtime_io::ed25519_verify(&s, msg.get(), &p))
+			.map(|s| s.verify(msg, &ed25519::Public::from_slice(signer.as_ref())))
 			.unwrap_or(false)
 	}
 }
@@ -398,7 +436,7 @@ impl From<&'static str> for DispatchError {
 
 /// Verify a signature on an encoded value in a lazy manner. This can be
 /// an optimization if the signature scheme has an "unsigned" escape hash.
-pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(sig: &V, item: &T, signer: &V::Signer) -> bool {
+pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(sig: &V, item: &T, signer: &<V::Signer as IdentifyAccount>::AccountId) -> bool {
 	// The `Lazy<T>` trait expresses something like `X: FnMut<Output = for<'a> &'a T>`.
 	// unfortunately this is a lifetime relationship that can't
 	// be expressed without generic associated types, better unification of HRTBs in type position,
diff --git a/substrate/core/sr-primitives/src/traits.rs b/substrate/core/sr-primitives/src/traits.rs
index 0497f094d26..4586a84511f 100644
--- a/substrate/core/sr-primitives/src/traits.rs
+++ b/substrate/core/sr-primitives/src/traits.rs
@@ -50,46 +50,84 @@ impl<'a> Lazy<[u8]> for &'a [u8] {
 	fn get(&mut self) -> &[u8] { &**self }
 }
 
+/// Some type that is able to be collapsed into an account ID. It is not possible to recreate the original value from
+/// the account ID.
+pub trait IdentifyAccount {
+	/// The account ID that this can be transformed into.
+	type AccountId;
+	/// Transform into an account.
+	fn into_account(self) -> Self::AccountId;
+}
+
+impl IdentifyAccount for primitives::ed25519::Public {
+	type AccountId = Self;
+	fn into_account(self) -> Self { self }
+}
+
+impl IdentifyAccount for primitives::sr25519::Public {
+	type AccountId = Self;
+	fn into_account(self) -> Self { self }
+}
+
+impl IdentifyAccount for primitives::ecdsa::Public {
+	type AccountId = Self;
+	fn into_account(self) -> Self { self }
+}
+
 /// Means of signature verification.
 pub trait Verify {
 	/// Type of the signer.
-	type Signer;
+	type Signer: IdentifyAccount;
 	/// Verify a signature. Return `true` if signature is valid for the value.
-	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool;
+	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &<Self::Signer as IdentifyAccount>::AccountId) -> bool;
 }
 
 impl Verify for primitives::ed25519::Signature {
 	type Signer = primitives::ed25519::Public;
-	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
+	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &primitives::ed25519::Public) -> bool {
 		runtime_io::ed25519_verify(self, msg.get(), signer)
 	}
 }
 
 impl Verify for primitives::sr25519::Signature {
 	type Signer = primitives::sr25519::Public;
-	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &Self::Signer) -> bool {
+	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &primitives::sr25519::Public) -> bool {
 		runtime_io::sr25519_verify(self, msg.get(), signer)
 	}
 }
 
+impl Verify for primitives::ecdsa::Signature {
+	type Signer = primitives::ecdsa::Public;
+	fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &primitives::ecdsa::Public) -> bool {
+		match runtime_io::secp256k1_ecdsa_recover_compressed(self.as_ref(), &runtime_io::blake2_256(msg.get())) {
+			Ok(pubkey) => <dyn AsRef<[u8]>>::as_ref(signer) == &pubkey[..],
+			_ => false,
+		}
+	}
+}
+
 /// Means of signature verification of an application key.
 pub trait AppVerify {
 	/// Type of the signer.
-	type Signer;
+	type AccountId;
 	/// Verify a signature. Return `true` if signature is valid for the value.
-	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool;
+	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::AccountId) -> bool;
 }
 
 impl<
 	S: Verify<Signer=<<T as AppKey>::Public as app_crypto::AppPublic>::Generic> + From<T>,
 	T: app_crypto::Wraps<Inner=S> + app_crypto::AppKey + app_crypto::AppSignature +
 		AsRef<S> + AsMut<S> + From<S>,
-> AppVerify for T {
-	type Signer = <T as AppKey>::Public;
-	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool {
+> AppVerify for T where
+	<S as Verify>::Signer: IdentifyAccount<AccountId = <S as Verify>::Signer>,
+	<<T as AppKey>::Public as app_crypto::AppPublic>::Generic:
+		IdentifyAccount<AccountId = <<T as AppKey>::Public as app_crypto::AppPublic>::Generic>,
+{
+	type AccountId = <T as AppKey>::Public;
+	fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &<T as AppKey>::Public) -> bool {
 		use app_crypto::IsWrappedBy;
 		let inner: &S = self.as_ref();
-		let inner_pubkey = <Self::Signer as app_crypto::AppPublic>::Generic::from_ref(&signer);
+		let inner_pubkey = <<T as AppKey>::Public as app_crypto::AppPublic>::Generic::from_ref(&signer);
 		Verify::verify(inner, msg, inner_pubkey)
 	}
 }
@@ -1179,6 +1217,21 @@ mod tests {
 	use super::AccountIdConversion;
 	use crate::codec::{Encode, Decode, Input};
 
+	mod t {
+		use primitives::crypto::KeyTypeId;
+		use app_crypto::{app_crypto, sr25519};
+		app_crypto!(sr25519, KeyTypeId(*b"test"));
+	}
+
+	#[test]
+	fn app_verify_works() {
+		use t::*;
+		use super::AppVerify;
+
+		let s = Signature::default();
+		let _ = s.verify(&[0u8; 100][..], &Public::default());
+	}
+
 	#[derive(Encode, Decode, Default, PartialEq, Debug)]
 	struct U32Value(u32);
 	impl super::TypeId for U32Value {
diff --git a/substrate/node/cli/src/chain_spec.rs b/substrate/node/cli/src/chain_spec.rs
index bc9f1e615fe..07f6946baf1 100644
--- a/substrate/node/cli/src/chain_spec.rs
+++ b/substrate/node/cli/src/chain_spec.rs
@@ -17,7 +17,7 @@
 //! Substrate chain configurations.
 
 use chain_spec::ChainSpecExtension;
-use primitives::{Pair, Public, crypto::UncheckedInto};
+use primitives::{Pair, Public, crypto::UncheckedInto, sr25519};
 use serde::{Serialize, Deserialize};
 use node_runtime::{
 	AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig,
@@ -32,10 +32,13 @@ use substrate_telemetry::TelemetryEndpoints;
 use grandpa_primitives::{AuthorityId as GrandpaId};
 use babe_primitives::{AuthorityId as BabeId};
 use im_online::sr25519::{AuthorityId as ImOnlineId};
-use sr_primitives::Perbill;
+use sr_primitives::{traits::Verify, Perbill};
 
-pub use node_primitives::{AccountId, Balance};
+pub use node_primitives::{AccountId, Balance, Signature};
 pub use node_runtime::GenesisConfig;
+use sr_primitives::traits::IdentifyAccount;
+
+type AccountPublic = <Signature as Verify>::Signer;
 
 const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
 
@@ -72,9 +75,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
 
 	let initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId, ImOnlineId)> = vec![(
 		// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
-		hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(),
+		hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(),
 		// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
-		hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].unchecked_into(),
+		hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(),
 		// 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC
 		hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"].unchecked_into(),
 		// 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8
@@ -83,9 +86,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
 		hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"].unchecked_into(),
 	),(
 		// 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2
-		hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].unchecked_into(),
+		hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(),
 		// 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF
-		hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].unchecked_into(),
+		hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(),
 		// 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE
 		hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"].unchecked_into(),
 		// 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ
@@ -94,9 +97,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
 		hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"].unchecked_into(),
 	),(
 		// 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp
-		hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].unchecked_into(),
+		hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(),
 		// 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9
-		hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].unchecked_into(),
+		hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(),
 		// 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d
 		hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"].unchecked_into(),
 		// 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH
@@ -105,9 +108,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
 		hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"].unchecked_into(),
 	),(
 		// 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9
-		hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].unchecked_into(),
+		hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(),
 		// 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn
-		hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].unchecked_into(),
+		hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(),
 		// 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4
 		hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"].unchecked_into(),
 		// 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x
@@ -120,7 +123,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
 	let root_key: AccountId = hex![
 		// 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo
 		"9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809"
-	].unchecked_into();
+	].into();
 
 	let endowed_accounts: Vec<AccountId> = vec![root_key.clone()];
 
@@ -154,12 +157,18 @@ pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Pu
 		.public()
 }
 
+/// Helper function to generate an account ID from seed
+pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId where
+	AccountPublic: From<<TPublic::Pair as Pair>::Public>
+{
+	AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
+}
 
 /// Helper function to generate stash, controller and session key from seed
 pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId) {
 	(
-		get_from_seed::<AccountId>(&format!("{}//stash", seed)),
-		get_from_seed::<AccountId>(seed),
+		get_account_id_from_seed::<sr25519::Public>(&format!("{}//stash", seed)),
+		get_account_id_from_seed::<sr25519::Public>(seed),
 		get_from_seed::<GrandpaId>(seed),
 		get_from_seed::<BabeId>(seed),
 		get_from_seed::<ImOnlineId>(seed),
@@ -175,18 +184,18 @@ pub fn testnet_genesis(
 ) -> GenesisConfig {
 	let endowed_accounts: Vec<AccountId> = endowed_accounts.unwrap_or_else(|| {
 		vec![
-			get_from_seed::<AccountId>("Alice"),
-			get_from_seed::<AccountId>("Bob"),
-			get_from_seed::<AccountId>("Charlie"),
-			get_from_seed::<AccountId>("Dave"),
-			get_from_seed::<AccountId>("Eve"),
-			get_from_seed::<AccountId>("Ferdie"),
-			get_from_seed::<AccountId>("Alice//stash"),
-			get_from_seed::<AccountId>("Bob//stash"),
-			get_from_seed::<AccountId>("Charlie//stash"),
-			get_from_seed::<AccountId>("Dave//stash"),
-			get_from_seed::<AccountId>("Eve//stash"),
-			get_from_seed::<AccountId>("Ferdie//stash"),
+			get_account_id_from_seed::<sr25519::Public>("Alice"),
+			get_account_id_from_seed::<sr25519::Public>("Bob"),
+			get_account_id_from_seed::<sr25519::Public>("Charlie"),
+			get_account_id_from_seed::<sr25519::Public>("Dave"),
+			get_account_id_from_seed::<sr25519::Public>("Eve"),
+			get_account_id_from_seed::<sr25519::Public>("Ferdie"),
+			get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+			get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+			get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
+			get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
+			get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
+			get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
 		]
 	});
 
@@ -272,7 +281,7 @@ fn development_config_genesis() -> GenesisConfig {
 		vec![
 			get_authority_keys_from_seed("Alice"),
 		],
-		get_from_seed::<AccountId>("Alice"),
+		get_account_id_from_seed::<sr25519::Public>("Alice"),
 		None,
 		true,
 	)
@@ -298,7 +307,7 @@ fn local_testnet_genesis() -> GenesisConfig {
 			get_authority_keys_from_seed("Alice"),
 			get_authority_keys_from_seed("Bob"),
 		],
-		get_from_seed::<AccountId>("Alice"),
+		get_account_id_from_seed::<sr25519::Public>("Alice"),
 		None,
 		false,
 	)
@@ -330,7 +339,7 @@ pub(crate) mod tests {
 			vec![
 				get_authority_keys_from_seed("Alice"),
 			],
-			get_from_seed::<AccountId>("Alice"),
+			get_account_id_from_seed::<sr25519::Public>("Alice"),
 			None,
 			false,
 		)
diff --git a/substrate/node/cli/src/factory_impl.rs b/substrate/node/cli/src/factory_impl.rs
index 84c24f2af09..48fb7b237f1 100644
--- a/substrate/node/cli/src/factory_impl.rs
+++ b/substrate/node/cli/src/factory_impl.rs
@@ -25,16 +25,21 @@ use codec::{Encode, Decode};
 use keyring::sr25519::Keyring;
 use node_runtime::{
 	Call, CheckedExtrinsic, UncheckedExtrinsic, SignedExtra, BalancesCall, ExistentialDeposit,
-	MinimumPeriod,
+	MinimumPeriod
 };
+use node_primitives::Signature;
 use primitives::{sr25519, crypto::Pair};
-use sr_primitives::{generic::Era, traits::{Block as BlockT, Header as HeaderT, SignedExtension}};
+use sr_primitives::{
+	generic::Era, traits::{Block as BlockT, Header as HeaderT, SignedExtension, Verify, IdentifyAccount}
+};
 use transaction_factory::RuntimeAdapter;
 use transaction_factory::modes::Mode;
 use inherents::InherentData;
 use timestamp;
 use finality_tracker;
 
+type AccountPublic = <Signature as Verify>::Signer;
+
 pub struct FactoryState<N> {
 	block_no: N,
 
@@ -167,7 +172,7 @@ impl RuntimeAdapter for FactoryState<Number> {
 	}
 
 	fn master_account_id() -> Self::AccountId {
-		Keyring::Alice.pair().public()
+		Keyring::Alice.to_account_id()
 	}
 
 	fn master_account_secret() -> Self::Secret {
@@ -177,7 +182,7 @@ impl RuntimeAdapter for FactoryState<Number> {
 	/// Generates a random `AccountId` from `seed`.
 	fn gen_random_account_id(seed: &Self::Number) -> Self::AccountId {
 		let pair: sr25519::Pair = sr25519::Pair::from_seed(&gen_seed_bytes(*seed));
-		pair.public().into()
+		AccountPublic::from(pair.public()).into_account()
 	}
 
 	/// Generates a random `Secret` from `seed`.
diff --git a/substrate/node/cli/src/service.rs b/substrate/node/cli/src/service.rs
index 0f4a098f3d0..03d31c43924 100644
--- a/substrate/node/cli/src/service.rs
+++ b/substrate/node/cli/src/service.rs
@@ -330,17 +330,15 @@ mod tests {
 	use consensus_common::{
 		Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy, BlockImport,
 	};
-	use node_primitives::{Block, DigestItem};
-	use node_runtime::{BalancesCall, Call, UncheckedExtrinsic};
+	use node_primitives::{Block, DigestItem, Signature};
+	use node_runtime::{BalancesCall, Call, UncheckedExtrinsic, Address};
 	use node_runtime::constants::{currency::CENTS, time::SLOT_DURATION};
 	use codec::{Encode, Decode};
-	use primitives::{
-		crypto::Pair as CryptoPair,
-		sr25519::Public as AddressPublic, H256,
-	};
+	use primitives::{crypto::Pair as CryptoPair, H256};
 	use sr_primitives::{
 		generic::{BlockId, Era, Digest, SignedPayload},
 		traits::Block as BlockT,
+		traits::Verify,
 		OpaqueExtrinsic,
 	};
 	use timestamp;
@@ -348,6 +346,9 @@ mod tests {
 	use keyring::AccountKeyring;
 	use substrate_service::{AbstractService, Roles};
 	use crate::service::new_full;
+	use sr_primitives::traits::IdentifyAccount;
+
+	type AccountPublic = <Signature as Verify>::Signer;
 
 	#[cfg(feature = "rhd")]
 	fn test_sync() {
@@ -518,8 +519,8 @@ mod tests {
 			},
 			|service, _| {
 				let amount = 5 * CENTS;
-				let to = AddressPublic::from_raw(bob.public().0);
-				let from = AddressPublic::from_raw(charlie.public().0);
+				let to: Address = AccountPublic::from(bob.public()).into_account().into();
+				let from: Address = AccountPublic::from(charlie.public()).into_account().into();
 				let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
 				let best_block_id = BlockId::number(service.client().info().chain.best_number);
 				let version = service.client().runtime_version_at(&best_block_id).unwrap().spec_version;
diff --git a/substrate/node/primitives/src/lib.rs b/substrate/node/primitives/src/lib.rs
index 6b128db4f3d..b6a5ec05655 100644
--- a/substrate/node/primitives/src/lib.rs
+++ b/substrate/node/primitives/src/lib.rs
@@ -21,21 +21,20 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use sr_primitives::{
-	generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature
+	generic, traits::{Verify, BlakeTwo256, IdentifyAccount}, OpaqueExtrinsic, MultiSignature
 };
 
 /// An index to a block.
 pub type BlockNumber = u32;
 
 /// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
-pub type Signature = AnySignature;
+pub type Signature = MultiSignature;
 
 /// Some way of identifying an account on the chain. We intentionally make it equivalent
 /// to the public key of our transaction signing scheme.
-pub type AccountId = <Signature as Verify>::Signer;
+pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
 
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
+/// The type for looking up accounts. We don't expect more than 4 billion of them.
 pub type AccountIndex = u32;
 
 /// Balance of an account.
diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs
index a198877552d..d7008dd8932 100644
--- a/substrate/node/runtime/src/lib.rs
+++ b/substrate/node/runtime/src/lib.rs
@@ -42,7 +42,7 @@ use sr_primitives::curve::PiecewiseLinear;
 use sr_primitives::transaction_validity::TransactionValidity;
 use sr_primitives::weights::Weight;
 use sr_primitives::traits::{
-	self, BlakeTwo256, Block as BlockT, NumberFor, StaticLookup, SaturatedConversion,
+	BlakeTwo256, Block as BlockT, NumberFor, StaticLookup,
 };
 use version::RuntimeVersion;
 #[cfg(any(feature = "std", test))]
@@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// and set impl_version to equal spec_version. If only runtime
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
-	spec_version: 182,
-	impl_version: 182,
+	spec_version: 183,
+	impl_version: 183,
 	apis: RUNTIME_API_VERSIONS,
 };
 
@@ -455,34 +455,6 @@ impl finality_tracker::Trait for Runtime {
 	type ReportLatency = ReportLatency;
 }
 
-impl system::offchain::CreateTransaction<Runtime, UncheckedExtrinsic> for Runtime {
-	type Signature = Signature;
-
-	fn create_transaction<F: system::offchain::Signer<AccountId, Self::Signature>>(
-		call: Call,
-		account: AccountId,
-		index: Index,
-	) -> Option<(Call, <UncheckedExtrinsic as traits::Extrinsic>::SignaturePayload)> {
-		let period = 1 << 8;
-		let current_block = System::block_number().saturated_into::<u64>();
-		let tip = 0;
-		let extra: SignedExtra = (
-			system::CheckVersion::<Runtime>::new(),
-			system::CheckGenesis::<Runtime>::new(),
-			system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
-			system::CheckNonce::<Runtime>::from(index),
-			system::CheckWeight::<Runtime>::new(),
-			transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
-			Default::default(),
-		);
-		let raw_payload = SignedPayload::new(call, extra).ok()?;
-		let signature = F::sign(account.clone(), &raw_payload)?;
-		let address = Indices::unlookup(account);
-		let (call, extra, _) = raw_payload.deconstruct();
-		Some((call, (address, signature, extra)))
-	}
-}
-
 construct_runtime!(
 	pub enum Runtime where
 		Block = Block,
@@ -693,28 +665,3 @@ impl_runtime_apis! {
 		}
 	}
 }
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use sr_primitives::app_crypto::RuntimeAppPublic;
-	use system::offchain::SubmitSignedTransaction;
-
-	fn is_submit_signed_transaction<T, Signer>(_arg: T) where
-		T: SubmitSignedTransaction<
-			Runtime,
-			Call,
-			Extrinsic=UncheckedExtrinsic,
-			CreateTransaction=Runtime,
-			Signer=Signer,
-		>,
-		Signer: RuntimeAppPublic + From<AccountId>,
-		Signer::Signature: Into<Signature>,
-	{}
-
-	#[test]
-	fn validate_bounds() {
-		let x = SubmitTransaction::default();
-		is_submit_signed_transaction(x);
-	}
-}
diff --git a/substrate/node/testing/src/keyring.rs b/substrate/node/testing/src/keyring.rs
index 853ca0ef6d7..ca44a53880f 100644
--- a/substrate/node/testing/src/keyring.rs
+++ b/substrate/node/testing/src/keyring.rs
@@ -23,9 +23,7 @@ use sr_primitives::generic::Era;
 use codec::Encode;
 
 /// Alice's account id.
-pub fn alice() -> AccountId {
-	AccountKeyring::Alice.into()
-}
+pub fn alice() -> AccountId { AccountKeyring::Alice.into() }
 
 /// Bob's account id.
 pub fn bob() -> AccountId {
@@ -82,7 +80,7 @@ pub fn sign(xt: CheckedExtrinsic, version: u32, genesis_hash: [u8; 32]) -> Unche
 	match xt.signed {
 		Some((signed, extra)) => {
 			let payload = (xt.function, extra.clone(), version, genesis_hash, genesis_hash);
-			let key = AccountKeyring::from_public(&signed).unwrap();
+			let key = AccountKeyring::from_account_id(&signed).unwrap();
 			let signature = payload.using_encoded(|b| {
 				if b.len() > 256 {
 					key.sign(&sr_io::blake2_256(b))
diff --git a/substrate/srml/system/src/offchain.rs b/substrate/srml/system/src/offchain.rs
index e234c74c089..468c88af39d 100644
--- a/substrate/srml/system/src/offchain.rs
+++ b/substrate/srml/system/src/offchain.rs
@@ -21,71 +21,24 @@ use sr_primitives::app_crypto::RuntimeAppPublic;
 use sr_primitives::traits::Extrinsic as ExtrinsicT;
 
 /// A trait responsible for signing a payload using given account.
-pub trait Signer<Account, Signature> {
+pub trait Signer<Public, Signature> {
 	/// Sign any encodable payload with given account and produce a signature.
 	///
 	/// Returns `Some` if signing succeeded and `None` in case the `account` couldn't be used.
-	fn sign<Payload: Encode>(account: Account, payload: &Payload) -> Option<Signature>;
+	fn sign<Payload: Encode>(public: Public, payload: &Payload) -> Option<Signature>;
 }
 
-impl<Account, Signature, AppPublic> Signer<Account, Signature> for AppPublic where
-	AppPublic: RuntimeAppPublic + From<Account>,
+impl<Public, Signature, AppPublic> Signer<Public, Signature> for AppPublic where
+	AppPublic: RuntimeAppPublic + From<Public>,
 	AppPublic::Signature: Into<Signature>,
 {
-	fn sign<Payload: Encode>(account: Account, raw_payload: &Payload) -> Option<Signature> {
+	fn sign<Payload: Encode>(public: Public, raw_payload: &Payload) -> Option<Signature> {
 		raw_payload.using_encoded(|payload| {
-			AppPublic::from(account).sign(&payload).map(Into::into)
+			AppPublic::from(public).sign(&payload).map(Into::into)
 		})
 	}
 }
 
-/// Creates runtime-specific signed transaction.
-pub trait CreateTransaction<T: crate::Trait, Extrinsic: ExtrinsicT> {
-	type Signature;
-
-	/// Attempt to create signed extrinsic data that encodes call from given account.
-	///
-	/// Runtime implementation is free to construct the payload to sign and the signature
-	/// in any way it wants.
-	/// Returns `None` if signed extrinsic could not be created (either because signing failed
-	/// or because of any other runtime-specific reason).
-	fn create_transaction<F: Signer<T::AccountId, Self::Signature>>(
-		call: Extrinsic::Call,
-		account: T::AccountId,
-		nonce: T::Index,
-	) -> Option<(Extrinsic::Call, Extrinsic::SignaturePayload)>;
-}
-
-/// A trait to sign and submit transactions in offchain calls.
-pub trait SubmitSignedTransaction<T: crate::Trait, Call> {
-	/// Unchecked extrinsic type.
-	type Extrinsic: ExtrinsicT<Call=Call> + codec::Encode;
-
-	/// A runtime-specific type to produce signed data for the extrinsic.
-	type CreateTransaction: CreateTransaction<T, Self::Extrinsic>;
-
-	/// A type used to sign transactions created using `CreateTransaction`.
-	type Signer: Signer<
-		T::AccountId,
-		<Self::CreateTransaction as CreateTransaction<T, Self::Extrinsic>>::Signature,
-	>;
-
-	/// Sign given call and submit it to the transaction pool.
-	///
-	/// Returns `Ok` if the transaction was submitted correctly
-	/// and `Err` if the key for given `id` was not found or the
-	/// transaction was rejected from the pool.
-	fn sign_and_submit(call: impl Into<Call>, id: T::AccountId) -> Result<(), ()> {
-		let call = call.into();
-		let expected = <crate::Module<T>>::account_nonce(&id);
-		let (call, signature_data) = Self::CreateTransaction
-			::create_transaction::<Self::Signer>(call, id, expected)
-			.ok_or(())?;
-		let xt = Self::Extrinsic::new(call, Some(signature_data)).ok_or(())?;
-		runtime_io::submit_transaction(xt.encode())
-	}
-}
-
 /// A trait to submit unsigned transactions in offchain calls.
 pub trait SubmitUnsignedTransaction<T: crate::Trait, Call> {
 	/// Unchecked extrinsic type.
@@ -114,18 +67,6 @@ impl<S, C, E> Default for TransactionSubmitter<S, C, E> {
 	}
 }
 
-/// A blanket implementation to simplify creation of transaction signer & submitter in the runtime.
-impl<T, E, S, C, Call> SubmitSignedTransaction<T, Call> for TransactionSubmitter<S, C, E> where
-	T: crate::Trait,
-	C: CreateTransaction<T, E>,
-	S: Signer<T::AccountId, <C as CreateTransaction<T, E>>::Signature>,
-	E: ExtrinsicT<Call=Call> + codec::Encode,
-{
-	type Extrinsic = E;
-	type CreateTransaction = C;
-	type Signer = S;
-}
-
 /// A blanket impl to use the same submitter for usigned transactions as well.
 impl<T, E, S, C, Call> SubmitUnsignedTransaction<T, Call> for TransactionSubmitter<S, C, E> where
 	T: crate::Trait,
diff --git a/substrate/subkey/src/cli.yml b/substrate/subkey/src/cli.yml
index aa6c6d4a574..5d8cd11b1e6 100644
--- a/substrate/subkey/src/cli.yml
+++ b/substrate/subkey/src/cli.yml
@@ -12,6 +12,11 @@ args:
       long: sr25519
       help: Use Schnorr/Ristretto x25519/BIP39 cryptography
       takes_value: false
+  - secp256k1:
+      short: k
+      long: secp256k1
+      help: Use SECP256k1/ECDSA/BIP39 cryptography
+      takes_value: false
   - password:
       short: p
       long: password
diff --git a/substrate/subkey/src/main.rs b/substrate/subkey/src/main.rs
index 2596513ab28..1b537580f57 100644
--- a/substrate/subkey/src/main.rs
+++ b/substrate/subkey/src/main.rs
@@ -22,15 +22,15 @@ use bip39::{Language, Mnemonic, MnemonicType};
 use clap::{load_yaml, App, ArgMatches};
 use codec::{Decode, Encode};
 use hex_literal::hex;
-use node_primitives::{Balance, Hash, Index};
+use node_primitives::{Balance, Hash, Index, AccountId, Signature};
 use node_runtime::{BalancesCall, Call, Runtime, SignedPayload, UncheckedExtrinsic, VERSION};
 use primitives::{
 	crypto::{set_default_ss58_version, Ss58AddressFormat, Ss58Codec},
-	ed25519, sr25519, Pair, Public, H256, hexdisplay::HexDisplay,
+	ed25519, sr25519, ecdsa, Pair, Public, H256, hexdisplay::HexDisplay,
 };
-use sr_primitives::generic::Era;
+use sr_primitives::{traits::{IdentifyAccount, Verify}, generic::Era};
 use std::{
-	convert::TryInto,
+	convert::{TryInto, TryFrom},
 	io::{stdin, Read},
 	str::FromStr,
 };
@@ -43,8 +43,10 @@ trait Crypto: Sized {
 	fn pair_from_suri(suri: &str, password: Option<&str>) -> Self::Pair {
 		Self::Pair::from_string(suri, password).expect("Invalid phrase")
 	}
-	fn ss58_from_pair(pair: &Self::Pair) -> String {
-		pair.public().to_ss58check()
+	fn ss58_from_pair(pair: &Self::Pair) -> String where
+		<Self::Pair as Pair>::Public: PublicT,
+	{
+		pair.public().into_runtime().into_account().to_ss58check()
 	}
 	fn public_from_pair(pair: &Self::Pair) -> Self::Public {
 		pair.public()
@@ -58,28 +60,43 @@ trait Crypto: Sized {
 	{
 		if let Ok((pair, seed)) = Self::Pair::from_phrase(uri, password) {
 			let public_key = Self::public_from_pair(&pair);
-			println!("Secret phrase `{}` is account:\n  Secret seed: {}\n  Public key (hex): {}\n  Address (SS58): {}",
+			println!("Secret phrase `{}` is account:\n  \
+				Secret seed:      {}\n  \
+				Public key (hex): {}\n  \
+				Account ID:       {}\n  \
+				SS58 Address:     {}",
 				uri,
 				format_seed::<Self>(seed),
-				format_public_key::<Self>(public_key),
+				format_public_key::<Self>(public_key.clone()),
+				format_account_id::<Self>(public_key),
 				Self::ss58_from_pair(&pair)
 			);
-		} else if let Ok(pair) = Self::Pair::from_string(uri, password) {
+		} else if let Ok((pair, seed)) = Self::Pair::from_string_with_seed(uri, password) {
 			let public_key = Self::public_from_pair(&pair);
-			println!(
-				"Secret Key URI `{}` is account:\n  Public key (hex): {}\n  Address (SS58): {}",
+			println!("Secret Key URI `{}` is account:\n  \
+				Secret seed:      {}\n  \
+				Public key (hex): {}\n  \
+				Account ID:       {}\n  \
+				SS58 Address:     {}",
 				uri,
-				format_public_key::<Self>(public_key),
+				if let Some(seed) = seed { format_seed::<Self>(seed) } else { "n/a".into() },
+				format_public_key::<Self>(public_key.clone()),
+				format_account_id::<Self>(public_key),
 				Self::ss58_from_pair(&pair)
 			);
 		} else if let Ok((public_key, v)) =
 			<Self::Pair as Pair>::Public::from_string_with_version(uri)
 		{
 			let v = network_override.unwrap_or(v);
-			println!("Public Key URI `{}` is account:\n  Network ID/version: {}\n  Public key (hex): {}\n  Address (SS58): {}",
+			println!("Public Key URI `{}` is account:\n  \
+				Network ID/version: {}\n  \
+				Public key (hex):   {}\n  \
+				Account ID:         {}\n  \
+				SS58 Address:       {}",
 				uri,
 				String::from(v),
 				format_public_key::<Self>(public_key.clone()),
+				format_account_id::<Self>(public_key.clone()),
 				public_key.to_ss58check_with_version(v)
 			);
 		} else {
@@ -106,17 +123,37 @@ impl Crypto for Sr25519 {
 	type Public = sr25519::Public;
 }
 
+struct Ecdsa;
+
+impl Crypto for Ecdsa {
+	type Pair = ecdsa::Pair;
+	type Public = ecdsa::Public;
+}
+
 type SignatureOf<C> = <<C as Crypto>::Pair as Pair>::Signature;
 type PublicOf<C> = <<C as Crypto>::Pair as Pair>::Public;
 type SeedOf<C> = <<C as Crypto>::Pair as Pair>::Seed;
+type AccountPublic = <Signature as Verify>::Signer;
 
-trait SignatureT: AsRef<[u8]> + AsMut<[u8]> + Default {}
-trait PublicT: Sized + AsRef<[u8]> + Ss58Codec {}
+trait SignatureT: AsRef<[u8]> + AsMut<[u8]> + Default {
+	/// Converts the signature into a runtime account signature, if possible. If not possible, bombs out.
+	fn into_runtime(self) -> Signature {
+		panic!("This cryptography isn't supported for this runtime.")
+	}
+}
+trait PublicT: Sized + AsRef<[u8]> + Ss58Codec {
+	/// Converts the public key into a runtime account public key, if possible. If not possible, bombs out.
+	fn into_runtime(self) -> AccountPublic {
+		panic!("This cryptography isn't supported for this runtime.")
+	}
+}
 
-impl SignatureT for sr25519::Signature {}
-impl SignatureT for ed25519::Signature {}
-impl PublicT for sr25519::Public {}
-impl PublicT for ed25519::Public {}
+impl SignatureT for sr25519::Signature { fn into_runtime(self) -> Signature { self.into() } }
+impl SignatureT for ed25519::Signature { fn into_runtime(self) -> Signature { self.into() } }
+impl SignatureT for ecdsa::Signature { fn into_runtime(self) -> Signature { self.into() } }
+impl PublicT for sr25519::Public { fn into_runtime(self) -> AccountPublic { self.into() } }
+impl PublicT for ed25519::Public { fn into_runtime(self) -> AccountPublic { self.into() } }
+impl PublicT for ecdsa::Public { fn into_runtime(self) -> AccountPublic { self.into() } }
 
 fn main() {
 	let yaml = load_yaml!("cli.yml");
@@ -125,10 +162,12 @@ fn main() {
 		.get_matches();
 
 	if matches.is_present("ed25519") {
-		execute::<Ed25519>(matches)
-	} else {
-		execute::<Sr25519>(matches)
+		return execute::<Ed25519>(matches)
 	}
+	if matches.is_present("secp256k1") {
+		return execute::<Ecdsa>(matches)
+	}
+	return execute::<Sr25519>(matches)
 }
 
 fn execute<C: Crypto>(matches: ArgMatches)
@@ -165,7 +204,7 @@ where
 		("verify", Some(matches)) => {
 			let should_decode = matches.is_present("hex");
 			let message = read_message_from_stdin(should_decode);
-			let is_valid_signature = do_verify::<C>(matches, message, password);
+			let is_valid_signature = do_verify::<C>(matches, message);
 			if is_valid_signature {
 				println!("Signature verifies correctly.");
 			} else {
@@ -182,20 +221,20 @@ where
 			C::print_from_uri(&formated_seed, None, maybe_network);
 		}
 		("transfer", Some(matches)) => {
-			let signer = read_pair::<Sr25519>(matches.value_of("from"), password);
+			let signer = read_pair::<C>(matches.value_of("from"), password);
 			let index = read_required_parameter::<Index>(matches, "index");
 			let genesis_hash = read_genesis_hash(matches);
 
-			let to = read_public_key::<Sr25519>(matches.value_of("to"), password);
+			let to: AccountId = read_account_id(matches.value_of("to"));
 			let amount = read_required_parameter::<Balance>(matches, "amount");
 			let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
 
-			let extrinsic = create_extrinsic(function, index, signer, genesis_hash);
+			let extrinsic = create_extrinsic::<C>(function, index, signer, genesis_hash);
 
 			print_extrinsic(extrinsic);
 		}
 		("sign-transaction", Some(matches)) => {
-			let signer = read_pair::<Sr25519>(matches.value_of("suri"), password);
+			let signer = read_pair::<C>(matches.value_of("suri"), password);
 			let index = read_required_parameter::<Index>(matches, "nonce");
 			let genesis_hash = read_genesis_hash(matches);
 
@@ -205,7 +244,7 @@ where
 				.and_then(|x| Decode::decode(&mut &x[..]).ok())
 				.unwrap();
 
-			let extrinsic = create_extrinsic(function, index, signer, genesis_hash);
+			let extrinsic = create_extrinsic::<C>(function, index, signer, genesis_hash);
 
 			print_extrinsic(extrinsic);
 		}
@@ -236,13 +275,13 @@ where
 	format_signature::<C>(&signature)
 }
 
-fn do_verify<C: Crypto>(matches: &ArgMatches, message: Vec<u8>, password: Option<&str>) -> bool
+fn do_verify<C: Crypto>(matches: &ArgMatches, message: Vec<u8>) -> bool
 where
 	SignatureOf<C>: SignatureT,
 	PublicOf<C>: PublicT,
 {
 	let signature = read_signature::<C>(matches);
-	let pubkey = read_public_key::<C>(matches.value_of("uri"), password);
+	let pubkey = read_public_key::<C>(matches.value_of("uri"));
 	<<C as Crypto>::Pair as Pair>::verify(&signature, &message, &pubkey)
 }
 
@@ -305,9 +344,7 @@ where
 	signature
 }
 
-fn read_public_key<C: Crypto>(matched_uri: Option<&str>, password: Option<&str>) -> PublicOf<C>
-where
-	SignatureOf<C>: SignatureT,
+fn read_public_key<C: Crypto>(matched_uri: Option<&str>) -> PublicOf<C> where
 	PublicOf<C>: PublicT,
 {
 	let uri = matched_uri.expect("parameter is required; thus it can't be None; qed");
@@ -319,13 +356,28 @@ where
 	if let Ok(pubkey_vec) = hex::decode(uri) {
 		<C as Crypto>::Public::from_slice(pubkey_vec.as_slice())
 	} else {
-		<C as Crypto>::Pair::from_string(uri, password)
+		<C as Crypto>::Public::from_string(uri)
 			.ok()
-			.map(|p| p.public())
 			.expect("Invalid URI; expecting either a secret URI or a public URI.")
 	}
 }
 
+fn read_account_id(matched_uri: Option<&str>) -> AccountId {
+	let uri = matched_uri.expect("parameter is required; thus it can't be None; qed");
+	let uri = if uri.starts_with("0x") {
+		&uri[2..]
+	} else {
+		uri
+	};
+	if let Ok(data_vec) = hex::decode(uri) {
+		AccountId::try_from(data_vec.as_slice())
+			.expect("Invalid hex length for account ID; should be 32 bytes")
+	} else {
+		AccountId::from_ss58check(uri).ok()
+			.expect("Invalid SS58-check address given for account ID.")
+	}
+}
+
 fn read_pair<C: Crypto>(
 	matched_suri: Option<&str>,
 	password: Option<&str>,
@@ -350,12 +402,21 @@ fn format_public_key<C: Crypto>(public_key: PublicOf<C>) -> String {
 	format!("0x{}", HexDisplay::from(&public_key.as_ref()))
 }
 
-fn create_extrinsic(
+fn format_account_id<C: Crypto>(public_key: PublicOf<C>) -> String where
+	PublicOf<C>: PublicT,
+{
+	format!("0x{}", HexDisplay::from(&public_key.into_runtime().into_account().as_ref()))
+}
+
+fn create_extrinsic<C: Crypto>(
 	function: Call,
 	index: Index,
-	signer: <Sr25519 as Crypto>::Pair,
+	signer: C::Pair,
 	genesis_hash: H256,
-) -> UncheckedExtrinsic {
+) -> UncheckedExtrinsic where
+	PublicOf<C>: PublicT,
+	SignatureOf<C>: SignatureT,
+{
 	let extra = |i: Index, f: Balance| {
 		(
 			system::CheckVersion::<Runtime>::new(),
@@ -380,13 +441,14 @@ fn create_extrinsic(
 			(),
 		),
 	);
-	let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
+	let signature = raw_payload.using_encoded(|payload| signer.sign(payload)).into_runtime();
+	let signer = signer.public().into_runtime();
 	let (function, extra, _) = raw_payload.deconstruct();
 
 	UncheckedExtrinsic::new_signed(
 		function,
-		signer.public().into(),
-		signature.into(),
+		signer.into_account().into(),
+		signature,
 		extra,
 	)
 }
@@ -439,7 +501,7 @@ mod tests {
 
 		let matches = App::from_yaml(yaml).get_matches_from(arg_vec);
 		let matches = matches.subcommand().1.unwrap();
-		assert!(do_verify::<CryptoType>(matches, message, password));
+		assert!(do_verify::<CryptoType>(matches, message));
 	}
 
 	#[test]
diff --git a/substrate/subkey/src/vanity.rs b/substrate/subkey/src/vanity.rs
index b612bc470f3..835001a0aa9 100644
--- a/substrate/subkey/src/vanity.rs
+++ b/substrate/subkey/src/vanity.rs
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
-use super::Crypto;
+use super::{PublicOf, PublicT, Crypto};
 use primitives::Pair;
 use rand::{rngs::OsRng, RngCore};
 
@@ -62,7 +62,9 @@ fn calculate_score(_desired: &str, key: &str) -> usize {
 	0
 }
 
-pub(super) fn generate_key<C: Crypto>(desired: &str) -> Result<KeyPair<C>, &str> {
+pub(super) fn generate_key<C: Crypto>(desired: &str) -> Result<KeyPair<C>, &str> where
+		PublicOf<C>: PublicT,
+{
 	if desired.is_empty() {
 		return Err("Pattern must not be empty");
 	}
diff --git a/substrate/test-utils/chain-spec-builder/src/main.rs b/substrate/test-utils/chain-spec-builder/src/main.rs
index 22c5253b06f..8fdd282345b 100644
--- a/substrate/test-utils/chain-spec-builder/src/main.rs
+++ b/substrate/test-utils/chain-spec-builder/src/main.rs
@@ -22,7 +22,7 @@ use structopt::StructOpt;
 
 use keystore::{Store as Keystore};
 use node_cli::chain_spec::{self, AccountId};
-use primitives::{crypto::{Public, Ss58Codec}, traits::BareCryptoStore};
+use primitives::{sr25519, crypto::{Public, Ss58Codec}, traits::BareCryptoStore};
 
 /// A utility to easily create a testnet chain spec definition with a given set
 /// of authorities and endowed accounts and/or generate random accounts.
@@ -237,11 +237,11 @@ fn main() -> Result<(), String> {
 			}
 
 			let endowed_accounts = endowed_seeds.iter().map(|seed| {
-				chain_spec::get_from_seed::<AccountId>(seed)
+				chain_spec::get_account_id_from_seed::<sr25519::Public>(seed)
 					.to_ss58check()
 			}).collect();
 
-			let sudo_account = chain_spec::get_from_seed::<AccountId>(&sudo_seed)
+			let sudo_account = chain_spec::get_account_id_from_seed::<sr25519::Public>(&sudo_seed)
 				.to_ss58check();
 
 			(authority_seeds, endowed_accounts, sudo_account)
-- 
GitLab