Updated ethkey to the latest version

This commit is contained in:
debris 2016-06-20 10:02:02 +02:00
parent bf6308312e
commit 074311d95b
7 changed files with 103 additions and 26 deletions

View File

@ -21,7 +21,8 @@ Usage:
ethkey generate prefix <prefix> <iterations> [options] ethkey generate prefix <prefix> <iterations> [options]
ethkey generate brain <seed> [options] ethkey generate brain <seed> [options]
ethkey sign <secret> <message> ethkey sign <secret> <message>
ethkey verify <public> <signature> <message> ethkey verify public <public> <signature> <message>
ethkey verify address <address> <signature> <message>
ethkey [-h | --help] ethkey [-h | --help]
Options: Options:
@ -126,15 +127,32 @@ c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8
-- --
#### `verify <public> <signature> <message>` #### `verify public <public> <signature> <message>`
*Verify the signature.* *Verify the signature.*
- `<secret>` - ethereum public, 64 bytes long - `<public>` - ethereum public, 64 bytes long
- `<signature>` - message signature, 65 bytes long - `<signature>` - message signature, 65 bytes long
- `<message>` - message, 32 bytes long - `<message>` - message, 32 bytes long
``` ```
ethkey verify 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200 bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987 ethkey verify public 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200 bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987
```
```
true
```
--
#### `verify address <address> <signature> <message>`
*Verify the signature.*
- `<address>` - ethereum address, 20 bytes long
- `<signature>` - message signature, 65 bytes long
- `<message>` - message, 32 bytes long
```
ethkey verify address 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200 bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987
``` ```
``` ```

View File

@ -7,7 +7,7 @@ use std::{env, fmt, process};
use std::num::ParseIntError; use std::num::ParseIntError;
use docopt::Docopt; use docopt::Docopt;
use rustc_serialize::hex::{FromHex, FromHexError}; use rustc_serialize::hex::{FromHex, FromHexError};
use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, Secret, Message, Public, Signature, sign, verify}; use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, Secret, Message, Public, Signature, Address, sign, verify_public, verify_address};
pub const USAGE: &'static str = r#" pub const USAGE: &'static str = r#"
Ethereum keys generator. Ethereum keys generator.
@ -19,7 +19,8 @@ Usage:
ethkey generate prefix <prefix> <iterations> [options] ethkey generate prefix <prefix> <iterations> [options]
ethkey generate brain <seed> [options] ethkey generate brain <seed> [options]
ethkey sign <secret> <message> ethkey sign <secret> <message>
ethkey verify <public> <signature> <message> ethkey verify public <public> <signature> <message>
ethkey verify address <address> <signature> <message>
ethkey [-h | --help] ethkey [-h | --help]
Options: Options:
@ -47,12 +48,15 @@ struct Args {
cmd_brain: bool, cmd_brain: bool,
cmd_sign: bool, cmd_sign: bool,
cmd_verify: bool, cmd_verify: bool,
cmd_public: bool,
cmd_address: bool,
arg_prefix: String, arg_prefix: String,
arg_iterations: String, arg_iterations: String,
arg_seed: String, arg_seed: String,
arg_secret: String, arg_secret: String,
arg_message: String, arg_message: String,
arg_public: String, arg_public: String,
arg_address: String,
arg_signature: String, arg_signature: String,
flag_secret: bool, flag_secret: bool,
flag_public: bool, flag_public: bool,
@ -164,10 +168,17 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
let signature = try!(sign(&secret, &message)); let signature = try!(sign(&secret, &message));
Ok(format!("{}", signature)) Ok(format!("{}", signature))
} else if args.cmd_verify { } else if args.cmd_verify {
let public = try!(Public::from_str(&args.arg_public));
let signature = try!(Signature::from_str(&args.arg_signature)); let signature = try!(Signature::from_str(&args.arg_signature));
let message = try!(Message::from_str(&args.arg_message)); let message = try!(Message::from_str(&args.arg_message));
let ok = try!(verify(&public, &signature, &message)); let ok = if args.cmd_public {
let public = try!(Public::from_str(&args.arg_public));
try!(verify_public(&public, &signature, &message))
} else if args.cmd_address {
let address = try!(Address::from_str(&args.arg_address));
try!(verify_address(&address, &signature, &message))
} else {
unreachable!();
};
Ok(format!("{}", ok)) Ok(format!("{}", ok))
} else { } else {
unreachable!(); unreachable!();
@ -251,8 +262,19 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
} }
#[test] #[test]
fn verify_valid() { fn verify_valid_public() {
let command = vec!["ethkey", "verify", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"] let command = vec!["ethkey", "verify", "public", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "true".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn verify_valid_address() {
let command = vec!["ethkey", "verify", "address", "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<String>>(); .collect::<Vec<String>>();
@ -263,7 +285,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
#[test] #[test]
fn verify_invalid() { fn verify_invalid() {
let command = vec!["ethkey", "verify", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec986"] let command = vec!["ethkey", "verify", "public", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec986"]
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<String>>(); .collect::<Vec<String>>();

View File

@ -4,6 +4,13 @@ use rustc_serialize::hex::ToHex;
use keccak::Keccak256; use keccak::Keccak256;
use super::{Secret, Public, Address, SECP256K1, Error}; use super::{Secret, Public, Address, SECP256K1, Error};
pub fn public_to_address(public: &Public) -> Address {
let hash = public.keccak256();
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
}
/// secp256k1 key pair /// secp256k1 key pair
pub struct KeyPair { pub struct KeyPair {
secret: Secret, secret: Secret,
@ -60,10 +67,7 @@ impl KeyPair {
} }
pub fn address(&self) -> Address { pub fn address(&self) -> Address {
let hash = self.public.keccak256(); public_to_address(&self.public)
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
} }
} }

View File

@ -26,8 +26,8 @@ pub trait Generator {
pub use self::brain::Brain; pub use self::brain::Brain;
pub use self::error::Error; pub use self::error::Error;
pub use self::keypair::KeyPair; pub use self::keypair::{KeyPair, public_to_address};
pub use self::primitive::{Secret, Public, Address, Message}; pub use self::primitive::{Secret, Public, Address, Message};
pub use self::prefix::Prefix; pub use self::prefix::Prefix;
pub use self::random::Random; pub use self::random::Random;
pub use self::signature::{sign, verify, Signature}; pub use self::signature::{sign, verify_public, verify_address, recover, Signature};

View File

@ -4,7 +4,7 @@ use std::str::FromStr;
use secp256k1::{Message as SecpMessage, RecoverableSignature, RecoveryId, Error as SecpError}; use secp256k1::{Message as SecpMessage, RecoverableSignature, RecoveryId, Error as SecpError};
use secp256k1::key::{SecretKey, PublicKey}; use secp256k1::key::{SecretKey, PublicKey};
use rustc_serialize::hex::{ToHex, FromHex}; use rustc_serialize::hex::{ToHex, FromHex};
use {Secret, Public, SECP256K1, Error, Message}; use {Secret, Public, SECP256K1, Error, Message, public_to_address, Address};
#[repr(C)] #[repr(C)]
#[derive(Eq)] #[derive(Eq)]
@ -113,7 +113,7 @@ pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
Ok(Signature(data_arr)) Ok(Signature(data_arr))
} }
pub fn verify(public: &Public, signature: &Signature, message: &Message) -> Result<bool, Error> { pub fn verify_public(public: &Public, signature: &Signature, message: &Message) -> Result<bool, Error> {
let context = &SECP256K1; let context = &SECP256K1;
let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32)))); let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
let sig = rsig.to_standard(context); let sig = rsig.to_standard(context);
@ -132,11 +132,28 @@ pub fn verify(public: &Public, signature: &Signature, message: &Message) -> Resu
} }
} }
pub fn verify_address(address: &Address, signature: &Signature, message: &Message) -> Result<bool, Error> {
let public = try!(recover(signature, message));
let recovered_address = public_to_address(&public);
Ok(address == &recovered_address)
}
pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error> {
let context = &SECP256K1;
let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
let pubkey = try!(context.recover(&try!(SecpMessage::from_slice(&message[..])), &rsig));
let serialized = pubkey.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
Ok(public)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
use {Generator, Random, Message}; use {Generator, Random, Message};
use super::{sign, verify, Signature}; use super::{sign, verify_public, verify_address, recover, Signature};
#[test] #[test]
fn signature_to_and_from_str() { fn signature_to_and_from_str() {
@ -149,10 +166,26 @@ mod tests {
} }
#[test] #[test]
fn sign_and_verify() { fn sign_and_recover_public() {
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let message = Message::default(); let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap(); let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify(keypair.public(), &signature, &message).unwrap()); assert_eq!(keypair.public(), &recover(&signature, &message).unwrap());
}
#[test]
fn sign_and_verify_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
}
#[test]
fn sign_and_verify_address() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_address(&keypair.address(), &signature, &message).unwrap());
} }
} }

View File

@ -154,7 +154,7 @@ impl SafeAccount {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ethkey::{Generator, Random, verify, Message}; use ethkey::{Generator, Random, verify_public, Message};
use super::{Crypto, SafeAccount}; use super::{Crypto, SafeAccount};
#[test] #[test]
@ -174,13 +174,13 @@ mod tests {
} }
#[test] #[test]
fn sign_and_verify() { fn sign_and_verify_public() {
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let password = "hello world"; let password = "hello world";
let message = Message::default(); let message = Message::default();
let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240); let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240);
let signature = account.sign(password, &message).unwrap(); let signature = account.sign(password, &message).unwrap();
assert!(verify(keypair.public(), &signature, &message).unwrap()); assert!(verify_public(keypair.public(), &signature, &message).unwrap());
} }
#[test] #[test]

View File

@ -1,5 +1,5 @@
//! ethkey reexport to make documentation look pretty. //! ethkey reexport to make documentation look pretty.
pub use _ethkey::{Address, Message, Signature, Public, Secret, Generator, sign, verify, Error, KeyPair, Random, Prefix}; pub use _ethkey::*;
use json; use json;
impl Into<json::H160> for Address { impl Into<json::H160> for Address {