secret store separated from util (#1304)

* bump rust-crypto

* initial version of account provider utilizing secret store

* update lazy_static to latest version

* AccountProvider accounts method

* new AccountProvider tests in progress

* basic tests for new AccountProvider

* ethcore compiles with new account provider and secret store

* ethcore-rpc build now compiling with new AccountProvider

* most rpc tests passing with new accounts_provider

* fixed basic_authority tests

* fixed eth_transaction_count rpc test

* fixed mocked/eth.rs tests

* fixed personal tests

* fixed personal signer rpc tests

* removed warnings

* parity compiling fine with new sstore

* fixed import direction

* do not unlock temporarily when we have the password

* removed TODO in account import

* display warning on auto account import failure

* fixed compiling of ethstore on windows

* ethstore as a part of parity repo

* added ethkey
This commit is contained in:
Marek Kotewicz
2016-06-20 00:10:34 +02:00
committed by Gav Wood
parent 08522eec37
commit 6b074e8fb2
84 changed files with 4027 additions and 2682 deletions

274
ethkey/src/bin/ethkey.rs Normal file
View File

@@ -0,0 +1,274 @@
extern crate docopt;
extern crate rustc_serialize;
extern crate ethkey;
use std::str::FromStr;
use std::{env, fmt, process};
use std::num::ParseIntError;
use docopt::Docopt;
use rustc_serialize::hex::{FromHex, FromHexError};
use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, Secret, Message, Public, Signature, sign, verify};
pub const USAGE: &'static str = r#"
Ethereum keys generator.
Copyright 2016 Ethcore (UK) Limited
Usage:
ethkey info <secret> [options]
ethkey generate random [options]
ethkey generate prefix <prefix> <iterations> [options]
ethkey generate brain <seed> [options]
ethkey sign <secret> <message>
ethkey verify <public> <signature> <message>
ethkey [-h | --help]
Options:
-h, --help Display this message and exit.
-s, --secret Display only the secret.
-p, --public Display only the public.
-a, --address Display only the address.
Commands:
info Display public and address of the secret.
generate Generates new ethereum key.
random Random generation.
prefix Random generation, but address must start with a prefix
brain Generate new key from string seed.
sign Sign message using secret.
verify Verify signer of the signature.
"#;
#[derive(Debug, RustcDecodable)]
struct Args {
cmd_info: bool,
cmd_generate: bool,
cmd_random: bool,
cmd_prefix: bool,
cmd_brain: bool,
cmd_sign: bool,
cmd_verify: bool,
arg_prefix: String,
arg_iterations: String,
arg_seed: String,
arg_secret: String,
arg_message: String,
arg_public: String,
arg_signature: String,
flag_secret: bool,
flag_public: bool,
flag_address: bool,
}
#[derive(Debug)]
enum Error {
Ethkey(EthkeyError),
FromHex(FromHexError),
ParseInt(ParseIntError),
}
impl From<EthkeyError> for Error {
fn from(err: EthkeyError) -> Self {
Error::Ethkey(err)
}
}
impl From<FromHexError> for Error {
fn from(err: FromHexError) -> Self {
Error::FromHex(err)
}
}
impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Self {
Error::ParseInt(err)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::Ethkey(ref e) => write!(f, "{}", e),
Error::FromHex(ref e) => write!(f, "{}", e),
Error::ParseInt(ref e) => write!(f, "{}", e),
}
}
}
enum DisplayMode {
KeyPair,
Secret,
Public,
Address,
}
impl DisplayMode {
fn new(args: &Args) -> Self {
if args.flag_secret {
DisplayMode::Secret
} else if args.flag_public {
DisplayMode::Public
} else if args.flag_address {
DisplayMode::Address
} else {
DisplayMode::KeyPair
}
}
}
fn main() {
match execute(env::args()) {
Ok(ok) => println!("{}", ok),
Err(err) => {
println!("{}", err);
process::exit(1);
},
}
}
fn display(keypair: KeyPair, mode: DisplayMode) -> String {
match mode {
DisplayMode::KeyPair => format!("{}", keypair),
DisplayMode::Secret => format!("{}", keypair.secret()),
DisplayMode::Public => format!("{}", keypair.public()),
DisplayMode::Address => format!("{}", keypair.address()),
}
}
fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.argv(command).decode())
.unwrap_or_else(|e| e.exit());
return if args.cmd_info {
let display_mode = DisplayMode::new(&args);
let secret = try!(Secret::from_str(&args.arg_secret));
let keypair = try!(KeyPair::from_secret(secret));
Ok(display(keypair, display_mode))
} else if args.cmd_generate {
let display_mode = DisplayMode::new(&args);
let keypair = if args.cmd_random {
Random.generate()
} else if args.cmd_prefix {
let prefix = try!(args.arg_prefix.from_hex());
let iterations = try!(usize::from_str_radix(&args.arg_iterations, 10));
Prefix::new(prefix, iterations).generate()
} else if args.cmd_brain {
Brain::new(args.arg_seed).generate()
} else {
unreachable!();
};
Ok(display(try!(keypair), display_mode))
} else if args.cmd_sign {
let secret = try!(Secret::from_str(&args.arg_secret));
let message = try!(Message::from_str(&args.arg_message));
let signature = try!(sign(&secret, &message));
Ok(format!("{}", signature))
} else if args.cmd_verify {
let public = try!(Public::from_str(&args.arg_public));
let signature = try!(Signature::from_str(&args.arg_signature));
let message = try!(Message::from_str(&args.arg_message));
let ok = try!(verify(&public, &signature, &message));
Ok(format!("{}", ok))
} else {
unreachable!();
}
}
#[cfg(test)]
mod tests {
use super::execute;
#[test]
fn info() {
let command = vec!["ethkey", "info", "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected =
"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn brain() {
let command = vec!["ethkey", "generate", "brain", "this is sparta"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected =
"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn secret() {
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--secret"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn public() {
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--public"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn address() {
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--address"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn sign() {
let command = vec!["ethkey", "sign", "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec987"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
#[test]
fn verify_valid() {
let command = vec!["ethkey", "verify", "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_invalid() {
let command = vec!["ethkey", "verify", "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124", "c1878cf60417151c766a712653d26ef350c8c75393458b7a9be715f053215af63dfd3b02c2ae65a8677917a8efa3172acb71cb90196e42106953ea0363c5aaf200", "bd50b7370c3f96733b31744c6c45079e7ae6c8d299613246d28ebcef507ec986"]
.into_iter()
.map(Into::into)
.collect::<Vec<String>>();
let expected = "false".to_owned();
assert_eq!(execute(command).unwrap(), expected);
}
}

5
ethkey/src/bin/main.rs Normal file
View File

@@ -0,0 +1,5 @@
#[cfg(feature = "cli")]
include!("ethkey.rs");
#[cfg(not(feature = "cli"))]
fn main() {}

46
ethkey/src/brain.rs Normal file
View File

@@ -0,0 +1,46 @@
use keccak::Keccak256;
use super::{KeyPair, Error, Generator, Secret};
/// Simple brainwallet.
pub struct Brain(String);
impl Brain {
pub fn new(s: String) -> Self {
Brain(s)
}
}
impl Generator for Brain {
fn generate(self) -> Result<KeyPair, Error> {
let seed = self.0;
let mut secret = seed.bytes().collect::<Vec<u8>>().keccak256();
let mut i = 0;
loop {
secret = secret.keccak256();
match i > 16384 {
false => i += 1,
true => {
let result = KeyPair::from_secret(Secret::from(secret.clone()));
if result.is_ok() {
return result
}
},
}
}
}
}
#[cfg(test)]
mod tests {
use {Brain, Generator};
#[test]
fn test_brain() {
let words = "this is sparta!".to_owned();
let first_keypair = Brain(words.clone()).generate().unwrap();
let second_keypair = Brain(words.clone()).generate().unwrap();
assert_eq!(first_keypair.secret(), second_keypair.secret());
}
}

53
ethkey/src/error.rs Normal file
View File

@@ -0,0 +1,53 @@
use std::fmt;
#[derive(Debug)]
/// Crypto error
pub enum Error {
/// Invalid secret key
InvalidSecret,
/// Invalid public key
InvalidPublic,
/// Invalid address
InvalidAddress,
/// Invalid EC signature
InvalidSignature,
/// Invalid AES message
InvalidMessage,
/// IO Error
Io(::std::io::Error),
/// Custom
Custom(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
Error::InvalidSecret => "Invalid secret key".into(),
Error::InvalidPublic => "Invalid public key".into(),
Error::InvalidAddress => "Invalid address".into(),
Error::InvalidSignature => "Invalid EC signature".into(),
Error::InvalidMessage => "Invalid AES message".into(),
Error::Io(ref err) => format!("I/O error: {}", err),
Error::Custom(ref s) => s.clone(),
};
f.write_fmt(format_args!("Crypto error ({})", msg))
}
}
impl From<::secp256k1::Error> for Error {
fn from(e: ::secp256k1::Error) -> Error {
match e {
::secp256k1::Error::InvalidMessage => Error::InvalidMessage,
::secp256k1::Error::InvalidPublicKey => Error::InvalidPublic,
::secp256k1::Error::InvalidSecretKey => Error::InvalidSecret,
_ => Error::InvalidSignature,
}
}
}
impl From<::std::io::Error> for Error {
fn from(err: ::std::io::Error) -> Error {
Error::Io(err)
}
}

15
ethkey/src/keccak.rs Normal file
View File

@@ -0,0 +1,15 @@
use tiny_keccak::Keccak;
pub trait Keccak256<T> {
fn keccak256(&self) -> T where T: Sized;
}
impl Keccak256<[u8; 32]> for [u8] {
fn keccak256(&self) -> [u8; 32] {
let mut keccak = Keccak::new_keccak256();
let mut result = [0u8; 32];
keccak.update(self);
keccak.finalize(&mut result);
result
}
}

91
ethkey/src/keypair.rs Normal file
View File

@@ -0,0 +1,91 @@
use std::fmt;
use secp256k1::key;
use rustc_serialize::hex::ToHex;
use keccak::Keccak256;
use super::{Secret, Public, Address, SECP256K1, Error};
/// secp256k1 key pair
pub struct KeyPair {
secret: Secret,
public: Public,
}
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(writeln!(f, "secret: {}", self.secret.to_hex()));
try!(writeln!(f, "public: {}", self.public.to_hex()));
write!(f, "address: {}", self.address().to_hex())
}
}
impl KeyPair {
/// Create a pair from secret key
pub fn from_secret(secret: Secret) -> Result<KeyPair, Error> {
let context = &SECP256K1;
let s: key::SecretKey = try!(key::SecretKey::from_slice(context, &secret[..]));
let pub_key = try!(key::PublicKey::from_secret_key(context, &s));
let serialized = pub_key.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
let keypair = KeyPair {
secret: secret,
public: public,
};
Ok(keypair)
}
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
let context = &SECP256K1;
let serialized = publ.serialize_vec(context, false);
let mut secret = Secret::default();
secret.copy_from_slice(&sec[0..32]);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
KeyPair {
secret: secret,
public: public,
}
}
pub fn secret(&self) -> &Secret {
&self.secret
}
pub fn public(&self) -> &Public {
&self.public
}
pub fn address(&self) -> Address {
let hash = self.public.keccak256();
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use {KeyPair, Secret};
#[test]
fn from_secret() {
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
let _ = KeyPair::from_secret(secret).unwrap();
}
#[test]
fn keypair_display() {
let expected =
"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65
public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4
address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned();
let secret = Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65").unwrap();
let kp = KeyPair::from_secret(secret).unwrap();
assert_eq!(format!("{}", kp), expected);
}
}

33
ethkey/src/lib.rs Normal file
View File

@@ -0,0 +1,33 @@
extern crate rand;
#[macro_use]
extern crate lazy_static;
extern crate tiny_keccak;
extern crate secp256k1;
extern crate rustc_serialize;
mod brain;
mod error;
mod keypair;
mod keccak;
mod prefix;
mod primitive;
mod random;
mod signature;
lazy_static! {
static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
}
/// Generates new keypair.
pub trait Generator {
/// Should be called to generate new keypair.
fn generate(self) -> Result<KeyPair, Error>;
}
pub use self::brain::Brain;
pub use self::error::Error;
pub use self::keypair::KeyPair;
pub use self::primitive::{Secret, Public, Address, Message};
pub use self::prefix::Prefix;
pub use self::random::Random;
pub use self::signature::{sign, verify, Signature};

41
ethkey/src/prefix.rs Normal file
View File

@@ -0,0 +1,41 @@
use super::{Random, Generator, KeyPair, Error};
/// Tries to find keypair with address starting with given prefix.
pub struct Prefix {
prefix: Vec<u8>,
iterations: usize,
}
impl Prefix {
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
Prefix {
prefix: prefix,
iterations: iterations,
}
}
}
impl Generator for Prefix {
fn generate(self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations {
let keypair = try!(Random.generate());
if keypair.address().starts_with(&self.prefix) {
return Ok(keypair)
}
}
Err(Error::Custom("Could not find keypair".into()))
}
}
#[cfg(test)]
mod tests {
use {Generator, Prefix};
#[test]
fn prefix_generator() {
let prefix = vec![0xffu8];
let keypair = Prefix::new(prefix.clone(), usize::max_value()).generate().unwrap();
assert!(keypair.address().starts_with(&prefix));
}
}

122
ethkey/src/primitive.rs Normal file
View File

@@ -0,0 +1,122 @@
use std::ops::{Deref, DerefMut};
use std::{fmt, cmp, hash};
use std::str::FromStr;
use rustc_serialize::hex::{ToHex, FromHex};
use Error;
macro_rules! impl_primitive {
($name: ident, $size: expr, $err: expr) => {
#[repr(C)]
#[derive(Eq)]
pub struct $name([u8; $size]);
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_hex())
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_hex())
}
}
impl FromStr for $name {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.from_hex() {
Ok(ref hex) if hex.len() == $size => {
let mut res = $name::default();
res.copy_from_slice(hex);
Ok(res)
},
_ => Err($err)
}
}
}
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
let self_ref: &[u8] = &self.0;
let other_ref: &[u8] = &other.0;
self_ref == other_ref
}
}
impl PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
let self_ref: &[u8] = &self.0;
let other_ref: &[u8] = &other.0;
self_ref.partial_cmp(other_ref)
}
}
impl Ord for $name {
fn cmp(&self, other: &Self) -> cmp::Ordering {
let self_ref: &[u8] = &self.0;
let other_ref: &[u8] = &other.0;
self_ref.cmp(other_ref)
}
}
impl Clone for $name {
fn clone(&self) -> Self {
let mut res = Self::default();
res.copy_from_slice(&self.0);
res
}
}
impl Default for $name {
fn default() -> Self {
$name([0u8; $size])
}
}
impl From<[u8; $size]> for $name {
fn from(s: [u8; $size]) -> Self {
$name(s)
}
}
impl Into<[u8; $size]> for $name {
fn into(self) -> [u8; $size] {
self.0
}
}
impl hash::Hash for $name {
fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
let self_ref: &[u8] = &self.0;
self_ref.hash(state)
}
}
impl Deref for $name {
type Target = [u8; $size];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
}
}
impl_primitive!(Address, 20, Error::InvalidAddress);
impl_primitive!(Secret, 32, Error::InvalidSecret);
impl_primitive!(Message, 32, Error::InvalidMessage);
impl_primitive!(Public, 64, Error::InvalidPublic);
#[cfg(test)]
mod tests {
}

16
ethkey/src/random.rs Normal file
View File

@@ -0,0 +1,16 @@
use rand::os::OsRng;
use super::{Generator, KeyPair, Error, SECP256K1};
/// Randomly generates new keypair.
pub struct Random;
impl Generator for Random {
fn generate(self) -> Result<KeyPair, Error> {
let context = &SECP256K1;
let mut rng = try!(OsRng::new());
let (sec, publ) = try!(context.generate_keypair(&mut rng));
Ok(KeyPair::from_keypair(sec, publ))
}
}

158
ethkey/src/signature.rs Normal file
View File

@@ -0,0 +1,158 @@
use std::ops::{Deref, DerefMut};
use std::{mem, fmt};
use std::str::FromStr;
use secp256k1::{Message as SecpMessage, RecoverableSignature, RecoveryId, Error as SecpError};
use secp256k1::key::{SecretKey, PublicKey};
use rustc_serialize::hex::{ToHex, FromHex};
use {Secret, Public, SECP256K1, Error, Message};
#[repr(C)]
#[derive(Eq)]
pub struct Signature([u8; 65]);
impl Signature {
/// Get a slice into the 'r' portion of the data.
pub fn r(&self) -> &[u8] {
&self.0[0..32]
}
/// Get a slice into the 's' portion of the data.
pub fn s(&self) -> &[u8] {
&self.0[32..64]
}
/// Get the recovery byte.
pub fn v(&self) -> u8 {
self.0[64]
}
}
// manual implementation large arrays don't have trait impls by default.
// remove when integer generics exist
impl ::std::cmp::PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
&self.0[..] == &other.0[..]
}
}
// also manual for the same reason, but the pretty printing might be useful.
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("Signature")
.field("r", &self.0[0..32].to_hex())
.field("s", &self.0[32..64].to_hex())
.field("v", &self.0[64..65].to_hex())
.finish()
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_hex())
}
}
impl FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.from_hex() {
Ok(ref hex) if hex.len() == 65 => {
let mut data = [0; 65];
data.copy_from_slice(&hex[0..65]);
Ok(Signature(data))
},
_ => Err(Error::InvalidSignature)
}
}
}
impl Default for Signature {
fn default() -> Self {
Signature([0; 65])
}
}
impl From<[u8; 65]> for Signature {
fn from(s: [u8; 65]) -> Self {
Signature(s)
}
}
impl Into<[u8; 65]> for Signature {
fn into(self) -> [u8; 65] {
self.0
}
}
impl Deref for Signature {
type Target = [u8; 65];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Signature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
let context = &SECP256K1;
// no way to create from raw byte array.
let sec: &SecretKey = unsafe { mem::transmute(secret) };
let s = try!(context.sign_recoverable(&try!(SecpMessage::from_slice(&message[..])), sec));
let (rec_id, data) = s.serialize_compact(context);
let mut data_arr = [0; 65];
// no need to check if s is low, it always is
data_arr[0..64].copy_from_slice(&data[0..64]);
data_arr[64] = rec_id.to_i32() as u8;
Ok(Signature(data_arr))
}
pub fn verify(public: &Public, signature: &Signature, message: &Message) -> Result<bool, Error> {
let context = &SECP256K1;
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 pdata: [u8; 65] = {
let mut temp = [4u8; 65];
temp[1..65].copy_from_slice(public.deref());
temp
};
let publ = try!(PublicKey::from_slice(context, &pdata));
match context.verify(&try!(SecpMessage::from_slice(&message[..])), &sig, &publ) {
Ok(_) => Ok(true),
Err(SecpError::IncorrectSignature) => Ok(false),
Err(x) => Err(Error::from(x))
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use {Generator, Random, Message};
use super::{sign, verify, Signature};
#[test]
fn signature_to_and_from_str() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
let string = format!("{}", signature);
let deserialized = Signature::from_str(&string).unwrap();
assert_eq!(signature, deserialized);
}
#[test]
fn sign_and_verify() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify(keypair.public(), &signature, &message).unwrap());
}
}