Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Key generation utility #176

Merged
merged 11 commits into from
May 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ members = [
"demo/executor",
"demo/cli",
"safe-mix",
"subkey",
]
exclude = [
"polkadot/runtime/wasm",
Expand Down
8 changes: 8 additions & 0 deletions subkey/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "subkey"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]

[dependencies]
ed25519 = { version = "*", path = "../substrate/ed25519" }
substrate-primitives = { version = "*", path = "../substrate/primitives" }
55 changes: 55 additions & 0 deletions subkey/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
extern crate ed25519;
extern crate substrate_primitives;

use std::env::args;
use ed25519::Pair;
use substrate_primitives::hexdisplay::HexDisplay;

fn good_waypoint(done: u64) -> u64 {
match done {
0 ... 1_000_000 => 100_000,
0 ... 10_000_000 => 1_000_000,
0 ... 100_000_000 => 10_000_000,
_ => 100_000_000,
}
}

fn main() {
if args().len() != 2 {
println!("Usage: subkey <search string>");
return;
}
let desired = args().last().unwrap();
let score = |s: &str| {
for truncate in 0..desired.len() - 1 {
let snip_size = desired.len() - truncate;
let truncated = &desired[0..snip_size];
if let Some(pos) = s.find(truncated) {
return (31 - pos) + (snip_size * 32);
}
}
0
};
let top = 30 + (desired.len() * 32);
let mut best = 0;
let mut seed = Pair::generate().public().0;
let mut done = 0;
loop {
let p = Pair::from_seed(&seed);
let ss58 = p.public().to_ss58check();
let s = score(&ss58);
if s > best {
println!("{}: {} ({}% complete)", ss58, HexDisplay::from(&seed), s * 100 / top);
best = s;
if best == top {
break;
}
}
seed = p.public().0;
done += 1;

if done % good_waypoint(done) == 0 {
println!("{} keys searched", done);
}
}
}
2 changes: 2 additions & 0 deletions substrate/ed25519/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ ring = "0.12"
untrusted = "0.5"
substrate-primitives = { version = "0.1", path = "../primitives" }
hex-literal = "0.1"
base58 = "0.1"
blake2-rfc = "0.2"
55 changes: 55 additions & 0 deletions substrate/ed25519/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
//! Simple Ed25519 API.

extern crate ring;
extern crate base58;
extern crate substrate_primitives as primitives;
extern crate untrusted;
extern crate blake2_rfc;

use ring::{rand, signature};
use primitives::hash::H512;
use base58::{ToBase58, FromBase58};

#[cfg(test)]
#[macro_use]
Expand Down Expand Up @@ -67,6 +70,14 @@ impl ::std::hash::Hash for Public {
}
}

#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum PublicError {
BadBase58,
BadLength,
UnknownVersion,
InvalidChecksum,
}

impl Public {
/// A new instance from the given 32-byte `data`.
pub fn from_raw(data: [u8; 32]) -> Self {
Expand All @@ -80,6 +91,24 @@ impl Public {
Public(r)
}

/// Some if the string is a properly encoded SS58Check address.
pub fn from_ss58check(s: &str) -> Result<Self, PublicError> {
let d = s.from_base58().map_err(|_| PublicError::BadBase58)?; // failure here would be invalid encoding.
if d.len() != 35 {
// Invalid length.
return Err(PublicError::BadLength);
}
if d[0] != 42 {
// Invalid version.
return Err(PublicError::UnknownVersion);
}
if d[33..35] != blake2_rfc::blake2b::blake2b(64, &[], &d[0..33]).as_bytes()[0..2] {
// Invalid checksum.
return Err(PublicError::InvalidChecksum);
}
Ok(Self::from_slice(&d[1..33]))
}

/// Return a `Vec<u8>` filled with raw data.
pub fn to_raw_vec(self) -> Vec<u8> {
let r: &[u8; 32] = self.as_ref();
Expand All @@ -96,6 +125,15 @@ impl Public {
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}

/// Return the ss58-check string for this key.
pub fn to_ss58check(&self) -> String {
let mut v = vec![42u8];
v.extend(self.as_slice());
let r = blake2_rfc::blake2b::blake2b(64, &[], &v);
v.extend(&r.as_bytes()[0..2]);
v.to_base58()
}
}

impl AsRef<[u8; 32]> for Public {
Expand Down Expand Up @@ -281,4 +319,21 @@ mod test {
let pair = Pair::generate();
let _pair2 = pair.derive_child_probably_bad(b"session_1234");
}

#[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);
}

#[test]
fn ss58check_known_works() {
let k = "5CGavy93sZgPPjHyziRohwVumxiHXMGmQLyuqQP4ZFx5vRU9";
let enc = hex!["090fa15cb5b1666222fff584b4cc2b1761fe1e238346b340491b37e25ea183ff"];
assert_eq!(Public::from_ss58check(k).unwrap(), Public::from_raw(enc));
}
}