KeyPair, EC signature
This commit is contained in:
parent
591bc3ef00
commit
e04907729a
@ -11,9 +11,13 @@ log = "0.3"
|
|||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
arrayvec = "0.3"
|
arrayvec = "0.3"
|
||||||
mio = "0.*"
|
mio = "0.4.4"
|
||||||
rand = "0.*"
|
rand = "0.3.12"
|
||||||
|
time = "0.1.34"
|
||||||
tiny-keccak = "0.3"
|
tiny-keccak = "0.3"
|
||||||
rocksdb = "0.2.1"
|
rocksdb = "0.2.1"
|
||||||
num = "0.1"
|
num = "0.1"
|
||||||
lazy_static = "0.1.*"
|
lazy_static = "0.1.*"
|
||||||
|
ifaces = { git = "https://github.com/dlevy47/rust-interfaces.git" }
|
||||||
|
secp256k1 = "0.5.1"
|
||||||
|
rust-crypto = "0.2.34"
|
||||||
|
167
src/crypto.rs
Normal file
167
src/crypto.rs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
use hash::*;
|
||||||
|
use secp256k1::Secp256k1;
|
||||||
|
use secp256k1::key;
|
||||||
|
use rand::os::OsRng;
|
||||||
|
|
||||||
|
pub type Secret=H256;
|
||||||
|
pub type Public=H512;
|
||||||
|
pub type Signature=H520;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CryptoError {
|
||||||
|
InvalidSecret,
|
||||||
|
InvalidPublic,
|
||||||
|
InvalidSignature,
|
||||||
|
InvalidMessage,
|
||||||
|
Io(::std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<::secp256k1::Error> for CryptoError {
|
||||||
|
fn from(e: ::secp256k1::Error) -> CryptoError {
|
||||||
|
match e {
|
||||||
|
::secp256k1::Error::InvalidMessage => CryptoError::InvalidMessage,
|
||||||
|
::secp256k1::Error::InvalidPublicKey => CryptoError::InvalidPublic,
|
||||||
|
::secp256k1::Error::InvalidSignature => CryptoError::InvalidSignature,
|
||||||
|
::secp256k1::Error::InvalidSecretKey => CryptoError::InvalidSecret,
|
||||||
|
_ => panic!("Crypto error: {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<::std::io::Error> for CryptoError {
|
||||||
|
fn from(err: ::std::io::Error) -> CryptoError {
|
||||||
|
CryptoError::Io(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
/// secp256k1 Key pair
|
||||||
|
///
|
||||||
|
/// Use `create()` to create a new random key pair.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util;
|
||||||
|
/// use ethcore_util::crypto::*;
|
||||||
|
/// use ethcore_util::hash::*;
|
||||||
|
/// fn main() {
|
||||||
|
/// let pair = KeyPair::create().unwrap();
|
||||||
|
/// let message = H256::random();
|
||||||
|
/// let signature = sign(pair.secret(), &message).unwrap();
|
||||||
|
///
|
||||||
|
/// assert!(verify(pair.public(), &signature, &message).unwrap());
|
||||||
|
/// assert_eq!(recover(&signature, &message).unwrap(), *pair.public());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub struct KeyPair {
|
||||||
|
secret: Secret,
|
||||||
|
public: Public,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPair {
|
||||||
|
/// Create a pair from secret key
|
||||||
|
pub fn from_secret(secret: Secret) -> Result<KeyPair, CryptoError> {
|
||||||
|
let context = Secp256k1::new();
|
||||||
|
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 p: Public = Public::from_slice(&serialized[1..65]);
|
||||||
|
Ok(KeyPair {
|
||||||
|
secret: secret,
|
||||||
|
public: p,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Create a new random key pair
|
||||||
|
pub fn create() -> Result<KeyPair, CryptoError> {
|
||||||
|
let context = Secp256k1::new();
|
||||||
|
let mut rng = try!(OsRng::new());
|
||||||
|
let (sec, publ) = try!(context.generate_keypair(&mut rng));
|
||||||
|
let serialized = publ.serialize_vec(&context, false);
|
||||||
|
let p: Public = Public::from_slice(&serialized[1..65]);
|
||||||
|
let s: Secret = unsafe { ::std::mem::transmute(sec) };
|
||||||
|
Ok(KeyPair {
|
||||||
|
secret: s,
|
||||||
|
public: p,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Returns public key
|
||||||
|
pub fn public(&self) -> &Public {
|
||||||
|
&self.public
|
||||||
|
}
|
||||||
|
/// Returns private key
|
||||||
|
pub fn secret(&self) -> &Secret {
|
||||||
|
&self.secret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recovers Public key from signed message hash.
|
||||||
|
pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> {
|
||||||
|
use secp256k1::*;
|
||||||
|
let context = Secp256k1::new();
|
||||||
|
let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
|
||||||
|
let publ = try!(context.recover(&try!(Message::from_slice(&message)), &rsig));
|
||||||
|
let serialized = publ.serialize_vec(&context, false);
|
||||||
|
let p: Public = Public::from_slice(&serialized[1..65]);
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
/// Returns siganture of message hash.
|
||||||
|
pub fn sign(secret: &Secret, message: &H256) -> Result<Signature, CryptoError> {
|
||||||
|
use secp256k1::*;
|
||||||
|
let context = Secp256k1::new();
|
||||||
|
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
|
||||||
|
let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec));
|
||||||
|
let (rec_id, data) = s.serialize_compact(&context);
|
||||||
|
let mut signature: ::crypto::Signature = unsafe { ::std::mem::uninitialized() };
|
||||||
|
signature.clone_from_slice(&data);
|
||||||
|
signature[64] = rec_id.to_i32() as u8;
|
||||||
|
Ok(signature)
|
||||||
|
}
|
||||||
|
/// Verify signature.
|
||||||
|
pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<bool, CryptoError> {
|
||||||
|
use secp256k1::*;
|
||||||
|
let context = Secp256k1::new();
|
||||||
|
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 mut pdata: [u8; 65] = [4u8; 65];
|
||||||
|
let ptr = pdata[1..].as_mut_ptr();
|
||||||
|
let src = public.as_ptr();
|
||||||
|
unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) };
|
||||||
|
let publ = try!(key::PublicKey::from_slice(&context, &pdata));
|
||||||
|
match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(Error::IncorrectSignature) => Ok(false),
|
||||||
|
Err(x) => Err(<CryptoError as From<Error>>::from(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
use hash::*;
|
||||||
|
use crypto::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_signature() {
|
||||||
|
let pair = KeyPair::create().unwrap();
|
||||||
|
let message = H256::random();
|
||||||
|
let signature = sign(pair.secret(), &message).unwrap();
|
||||||
|
|
||||||
|
assert!(verify(pair.public(), &signature, &message).unwrap());
|
||||||
|
assert_eq!(recover(&signature, &message).unwrap(), *pair.public());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_key() {
|
||||||
|
assert!(KeyPair::from_secret(Secret::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()).is_err());
|
||||||
|
assert!(KeyPair::from_secret(Secret::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap()).is_err());
|
||||||
|
assert!(KeyPair::from_secret(Secret::from_str("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141").unwrap()).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key() {
|
||||||
|
let pair = KeyPair::from_secret(Secret::from_str("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2").unwrap()).unwrap();
|
||||||
|
assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c");
|
||||||
|
}
|
||||||
|
}
|
66
src/hash.rs
66
src/hash.rs
@ -1,7 +1,8 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Index, IndexMut, BitOr, BitAnd};
|
use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd};
|
||||||
use rustc_serialize::hex::*;
|
use rustc_serialize::hex::*;
|
||||||
use error::EthcoreError;
|
use error::EthcoreError;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@ -16,6 +17,8 @@ pub trait FixedHash: Sized + BytesConvertable {
|
|||||||
fn randomize(&mut self);
|
fn randomize(&mut self);
|
||||||
fn size() -> usize;
|
fn size() -> usize;
|
||||||
fn mut_bytes(&mut self) -> &mut [u8];
|
fn mut_bytes(&mut self) -> &mut [u8];
|
||||||
|
fn from_slice(src: &[u8]) -> Self;
|
||||||
|
fn clone_from_slice(&mut self, src: &[u8]) -> usize;
|
||||||
fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash;
|
fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash;
|
||||||
fn bloom_part<T>(&self, m: usize) -> T where T: FixedHash;
|
fn bloom_part<T>(&self, m: usize) -> T where T: FixedHash;
|
||||||
fn contains_bloom<T>(&self, b: &T) -> bool where T: FixedHash;
|
fn contains_bloom<T>(&self, b: &T) -> bool where T: FixedHash;
|
||||||
@ -25,7 +28,7 @@ pub trait FixedHash: Sized + BytesConvertable {
|
|||||||
macro_rules! impl_hash {
|
macro_rules! impl_hash {
|
||||||
($from: ident, $size: expr) => {
|
($from: ident, $size: expr) => {
|
||||||
#[derive(Eq)]
|
#[derive(Eq)]
|
||||||
pub struct $from ([u8; $size]);
|
pub struct $from (pub [u8; $size]);
|
||||||
|
|
||||||
impl BytesConvertable for $from {
|
impl BytesConvertable for $from {
|
||||||
fn bytes(&self) -> &[u8] {
|
fn bytes(&self) -> &[u8] {
|
||||||
@ -33,6 +36,24 @@ macro_rules! impl_hash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for $from {
|
||||||
|
type Target = [u8];
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &[u8] {
|
||||||
|
unsafe {
|
||||||
|
::std::slice::from_raw_parts(self.0.as_ptr(), $size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DerefMut for $from {
|
||||||
|
#[inline]
|
||||||
|
fn deref_mut(&mut self) -> &mut [u8] {
|
||||||
|
unsafe {
|
||||||
|
::std::slice::from_raw_parts_mut(self.0.as_mut_ptr(), $size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FixedHash for $from {
|
impl FixedHash for $from {
|
||||||
fn new() -> $from {
|
fn new() -> $from {
|
||||||
$from([0; $size])
|
$from([0; $size])
|
||||||
@ -57,6 +78,23 @@ macro_rules! impl_hash {
|
|||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove once slice::clone_from_slice is stable
|
||||||
|
#[inline]
|
||||||
|
fn clone_from_slice(&mut self, src: &[u8]) -> usize {
|
||||||
|
let min = ::std::cmp::min($size, src.len());
|
||||||
|
let dst = &mut self.deref_mut()[.. min];
|
||||||
|
let src = &src[.. min];
|
||||||
|
for i in 0..min {
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
min
|
||||||
|
}
|
||||||
|
fn from_slice(src: &[u8]) -> Self {
|
||||||
|
let mut r = Self::new();
|
||||||
|
r.clone_from_slice(src);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash {
|
fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash {
|
||||||
let bp: Self = b.bloom_part($size);
|
let bp: Self = b.bloom_part($size);
|
||||||
let new_self = &bp | self;
|
let new_self = &bp | self;
|
||||||
@ -186,6 +224,30 @@ macro_rules! impl_hash {
|
|||||||
&mut self.0[index]
|
&mut self.0[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Index<ops::Range<usize>> for $from {
|
||||||
|
type Output = [u8];
|
||||||
|
|
||||||
|
fn index<'a>(&'a self, index: ops::Range<usize>) -> &'a [u8] {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl IndexMut<ops::Range<usize>> for $from {
|
||||||
|
fn index_mut<'a>(&'a mut self, index: ops::Range<usize>) -> &'a mut [u8] {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Index<ops::RangeFull> for $from {
|
||||||
|
type Output = [u8];
|
||||||
|
|
||||||
|
fn index<'a>(&'a self, _index: ops::RangeFull) -> &'a [u8] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl IndexMut<ops::RangeFull> for $from {
|
||||||
|
fn index_mut<'a>(&'a mut self, _index: ops::RangeFull) -> &'a mut [u8] {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// BitOr on references
|
/// BitOr on references
|
||||||
impl<'a> BitOr for &'a $from {
|
impl<'a> BitOr for &'a $from {
|
||||||
|
@ -14,8 +14,13 @@ extern crate log;
|
|||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
extern crate ifaces;
|
||||||
|
extern crate time;
|
||||||
|
extern crate crypto as rcrypto;
|
||||||
|
extern crate secp256k1;
|
||||||
|
extern crate arrayvec;
|
||||||
|
|
||||||
|
pub mod macros;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod uint;
|
pub mod uint;
|
||||||
@ -28,9 +33,9 @@ pub mod hashdb;
|
|||||||
pub mod memorydb;
|
pub mod memorydb;
|
||||||
pub mod overlaydb;
|
pub mod overlaydb;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
//pub mod filter;
|
|
||||||
pub mod chainfilter;
|
pub mod chainfilter;
|
||||||
pub mod trie;
|
pub mod trie;
|
||||||
|
pub mod crypto;
|
||||||
|
|
||||||
//pub mod network;
|
//pub mod network;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user