From 5fc87a334d35112dbc51f3f26a701bf9334ac219 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 7 Jan 2016 23:59:50 +0100 Subject: [PATCH] Additional work & convenience functions on crypto, bytes & hash. Renaming mut_bytes() to as_slice_mut(). --- src/bytes.rs | 18 ++++++++++++++- src/crypto.rs | 47 ++++++++++++++++++++++++++++++++++------ src/hash.rs | 42 +++++++++++++++++++++++++++++++---- src/rlp/rlpstream.rs | 7 ++++-- src/rlp/rlptraits.rs | 3 +++ src/rlp/untrusted_rlp.rs | 4 ++++ src/sha3.rs | 2 +- src/trie/triedbmut.rs | 2 +- 8 files changed, 109 insertions(+), 16 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index 1f1ee8c05..0e36a8c8a 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -306,10 +306,26 @@ impl FromBytes for T where T: FixedHash { use std::{mem, ptr}; let mut res: T = mem::uninitialized(); - ptr::copy(bytes.as_ptr(), res.mut_bytes().as_mut_ptr(), T::size()); + ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::size()); Ok(res) } } } +/// Simple trait to allow for raw population of a Sized object from a byte slice. +pub trait Populatable { + /// Populate self from byte slice `d` in a raw fashion. + fn populate_raw(&mut self, d: &[u8]); +} + +impl Populatable for T where T: Sized { + fn populate_raw(&mut self, d: &[u8]) { + use std::mem; + use std::slice; + use std::io::Write; + unsafe { + slice::from_raw_parts_mut(self as *mut T as *mut u8, mem::size_of::()) + }.write(&d).unwrap(); + } +} diff --git a/src/crypto.rs b/src/crypto.rs index 0d1ae9c05..9a1203921 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -3,9 +3,24 @@ use secp256k1::Secp256k1; use secp256k1::key; use rand::os::OsRng; -pub type Secret=H256; -pub type Public=H512; -pub type Signature=H520; +pub type Secret = H256; +pub type Public = H512; +pub type Signature = H520; + +impl Signature { + /// Create a new signature from the R, S and V componenets. + pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature { + use std::ptr; + let mut ret: Signature = Signature::new(); + unsafe { + let retslice: &mut [u8] = &mut ret; + ptr::copy(r.as_ptr(), retslice.as_mut_ptr(), 32); + ptr::copy(s.as_ptr(), retslice.as_mut_ptr().offset(32), 32); + } + ret[64] = v; + ret + } +} #[derive(Debug)] pub enum CryptoError { @@ -92,6 +107,9 @@ impl KeyPair { pub fn secret(&self) -> &Secret { &self.secret } + + /// Sign a message with our secret key. + pub fn sign(&self, message: &H256) -> Result { sign(&self.secret, message) } } /// Recovers Public key from signed message hash. @@ -102,8 +120,11 @@ pub fn recover(signature: &Signature, message: &H256) -> Result Result { use secp256k1::*; @@ -116,6 +137,16 @@ pub fn sign(secret: &Secret, message: &H256) -> Result { signature[64] = rec_id.to_i32() as u8; Ok(signature) } + +/// Check if each component of the signature is in range. +pub fn is_valid(sig: &Signature) -> bool { + sig[64] <= 1 && + H256::from_slice(&sig[0..32]) < h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") && + H256::from_slice(&sig[32..64]) < h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") && + H256::from_slice(&sig[32..64]) >= h256_from_u64(1) && + H256::from_slice(&sig[0..32]) >= h256_from_u64(1) +} + /// Verify signature. pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result { use secp256k1::*; @@ -142,6 +173,8 @@ mod tests { use hash::*; use crypto::*; + // TODO: tests for sign/recover roundtrip, at least. + #[test] fn test_signature() { let pair = KeyPair::create().unwrap(); @@ -154,14 +187,14 @@ mod tests { #[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()); + assert!(KeyPair::from_secret(h256_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")).is_err()); + assert!(KeyPair::from_secret(h256_from_hex("0000000000000000000000000000000000000000000000000000000000000000")).is_err()); + assert!(KeyPair::from_secret(h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")).is_err()); } #[test] fn test_key() { - let pair = KeyPair::from_secret(Secret::from_str("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2").unwrap()).unwrap(); + let pair = KeyPair::from_secret(h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2")).unwrap(); assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c"); } } diff --git a/src/hash.rs b/src/hash.rs index ea041f2ac..e6f9a61c7 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -5,6 +5,7 @@ use std::fmt; use std::ops; use std::hash::{Hash, Hasher}; use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd}; +use std::cmp::{PartialOrd, Ordering}; use rustc_serialize::hex::*; use error::EthcoreError; use rand::Rng; @@ -21,7 +22,7 @@ pub trait FixedHash: Sized + BytesConvertable { fn random() -> Self; fn randomize(&mut self); fn size() -> usize; - fn mut_bytes(&mut self) -> &mut [u8]; + fn as_slice_mut(&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; @@ -77,7 +78,7 @@ macro_rules! impl_hash { $size } - fn mut_bytes(&mut self) -> &mut [u8] { + fn as_slice_mut(&mut self) -> &mut [u8] { &mut self.0 } @@ -142,7 +143,7 @@ macro_rules! impl_hash { ptr += 1; } index &= mask; - ret.mut_bytes()[m - 1 - index / 8] |= 1 << (index % 8); + ret.as_slice_mut()[m - 1 - index / 8] |= 1 << (index % 8); } ret @@ -208,6 +209,19 @@ macro_rules! impl_hash { } } + impl PartialOrd for $from { + fn partial_cmp(&self, other: &Self) -> Option { + for i in 0..$size { + if self.0[i] > other.0[i] { + return Some(Ordering::Greater); + } else if self.0[i] < other.0[i] { + return Some(Ordering::Less); + } + } + Some(Ordering::Equal) + } + } + impl Hash for $from { fn hash(&self, state: &mut H) where H: Hasher { state.write(&self.0); @@ -311,7 +325,7 @@ macro_rules! impl_hash { } impl<'a> From<&'a U256> for H256 { - fn from(value: &'a U256) -> H256 { + fn from(value: &'a U256) -> H256 { unsafe { let mut ret: H256 = ::std::mem::uninitialized(); value.to_bytes(&mut ret); @@ -340,6 +354,26 @@ impl From
for H256 { } } +pub fn h256_from_hex(s: &str) -> H256 { + use std::str::FromStr; + H256::from_str(s).unwrap() +} + +pub fn h256_from_u64(n: u64) -> H256 { + use uint::U256; + H256::from(&U256::from(n)) +} + +pub fn address_from_hex(s: &str) -> Address { + use std::str::FromStr; + Address::from_str(s).unwrap() +} + +pub fn address_from_u64(n: u64) -> Address { + let h256 = h256_from_u64(n); + From::from(h256) +} + impl_hash!(H32, 4); impl_hash!(H64, 8); impl_hash!(H128, 16); diff --git a/src/rlp/rlpstream.rs b/src/rlp/rlpstream.rs index 43ae83a9a..3a19cab7d 100644 --- a/src/rlp/rlpstream.rs +++ b/src/rlp/rlpstream.rs @@ -193,8 +193,11 @@ impl Encoder for BasicEncoder { } } - fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () - { + fn emit_raw(&mut self, bytes: &[u8]) -> () { + self.bytes.append_slice(bytes); + } + + fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () { // get len before inserting a list let before_len = self.bytes.len(); diff --git a/src/rlp/rlptraits.rs b/src/rlp/rlptraits.rs index 067c438bf..5955e132d 100644 --- a/src/rlp/rlptraits.rs +++ b/src/rlp/rlptraits.rs @@ -5,6 +5,8 @@ pub trait Decoder: Sized { where F: FnOnce(&[u8]) -> Result; fn as_list(&self) -> Result, DecoderError>; + + fn as_raw(&self) -> &[u8]; } pub trait Decodable: Sized { @@ -185,6 +187,7 @@ pub trait View<'a, 'view>: Sized { pub trait Encoder { fn emit_value(&mut self, bytes: &[u8]) -> (); fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); + fn emit_raw(&mut self, bytes: &[u8]) -> (); } pub trait Encodable { diff --git a/src/rlp/untrusted_rlp.rs b/src/rlp/untrusted_rlp.rs index a8cecf09f..68956d8d0 100644 --- a/src/rlp/untrusted_rlp.rs +++ b/src/rlp/untrusted_rlp.rs @@ -305,6 +305,10 @@ impl<'a> Decoder for BasicDecoder<'a> { } } + fn as_raw(&self) -> &[u8] { + self.rlp.raw() + } + fn as_list(&self) -> Result, DecoderError> { let v: Vec> = self.rlp.iter() .map(| i | BasicDecoder::new(i)) diff --git a/src/sha3.rs b/src/sha3.rs index b3676720c..e1337c5f7 100644 --- a/src/sha3.rs +++ b/src/sha3.rs @@ -27,7 +27,7 @@ impl Hashable for T where T: BytesConvertable { let mut keccak = Keccak::new_keccak256(); keccak.update(self.bytes()); let mut ret: H256 = uninitialized(); - keccak.finalize(ret.mut_bytes()); + keccak.finalize(ret.as_slice_mut()); ret } } diff --git a/src/trie/triedbmut.rs b/src/trie/triedbmut.rs index 4c78e7667..e04b7c758 100644 --- a/src/trie/triedbmut.rs +++ b/src/trie/triedbmut.rs @@ -686,7 +686,7 @@ mod tests { 0 => encode(&j), _ => { let mut h = H256::new(); - h.mut_bytes()[31] = j as u8; + h.as_slice_mut()[31] = j as u8; encode(&h) }, }