From 6cf6ec642790f241d92944bc357eb021fd6fecf9 Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 6 Aug 2018 14:34:13 +0200 Subject: [PATCH 01/39] Switch rust-crypto crate to RustCrypto. Note that we use RustCrypto aes root crates : so if we build with RUSTFLAGS='-C target-feature=+aes,+ssse3,+sse2' on x86, AES native instruction will be used. Also added two Aes encryptor struct in preparation of switching (only two use case remaining at the time in 'network-devp2p' crate. --- parity-crypto/Cargo.toml | 8 +- parity-crypto/src/aes.rs | 160 +++++++++++++++++++++++++++--- parity-crypto/src/digest.rs | 23 +++-- parity-crypto/src/error.rs | 49 +++++++-- parity-crypto/src/lib.rs | 7 +- parity-crypto/src/scrypt.rs | 31 +++++- parity-crypto/test/content | 2 + parity-crypto/test/key1 | 1 + parity-crypto/test/left1_1 | 1 + parity-crypto/test/left1_2 | 1 + parity-crypto/test/pass1 | 1 + parity-crypto/test/result_128_cbc | Bin 0 -> 112 bytes parity-crypto/test/result_128_ctr | 3 + parity-crypto/test/right1_1 | 1 + parity-crypto/test/right1_2 | 1 + parity-crypto/test/salt1 | 1 + 16 files changed, 252 insertions(+), 38 deletions(-) create mode 100644 parity-crypto/test/content create mode 100644 parity-crypto/test/key1 create mode 100644 parity-crypto/test/left1_1 create mode 100644 parity-crypto/test/left1_2 create mode 100644 parity-crypto/test/pass1 create mode 100644 parity-crypto/test/result_128_cbc create mode 100644 parity-crypto/test/result_128_ctr create mode 100644 parity-crypto/test/right1_1 create mode 100644 parity-crypto/test/right1_2 create mode 100644 parity-crypto/test/salt1 diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 5c0af90f6..541dc9ed6 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -7,6 +7,10 @@ authors = ["Parity Technologies "] ethereum-types = "0.3" quick-error = "1.2.2" ring = "0.12" -rust-crypto = "0.2.36" tiny-keccak = "1.4" - +scrypt = "0.1.1" +ripemd160 = "0.7.0" +digest = "0.7" +aes = "0.2.0" +aes-ctr = "0.1.0" +block-modes = "0.1.0" diff --git a/parity-crypto/src/aes.rs b/parity-crypto/src/aes.rs index 42a26fad0..620ae4bcc 100644 --- a/parity-crypto/src/aes.rs +++ b/parity-crypto/src/aes.rs @@ -14,40 +14,174 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use block_modes::{ BlockMode, BlockModeIv }; +use block_modes::block_padding::Pkcs7; +use block_modes::block_padding::ZeroPadding; +use block_modes::{ Cbc, Ecb }; +use raes::{ Aes128, Aes256 }; +use aes_ctr::{ Aes128Ctr, Aes256Ctr }; +use aes_ctr::stream_cipher::{ NewFixStreamCipher, StreamCipherCore }; use error::SymmError; -use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; -use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; -use rcrypto::symmetriccipher::{Encryptor, Decryptor}; -use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; +use raes::block_cipher_trait::generic_array::GenericArray; + + +/// Reusable encoder/decoder for Ecb mode Aes256 with zero padding +pub struct AesEcb256(Ecb); + +impl AesEcb256 { + + /// New encoder/decoder, no iv for ecb + #[inline] + pub fn new(key: &[u8]) -> Result { + Ok(AesEcb256(Ecb::new_varkey(key)?)) + } + + #[inline] + pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { + self.0.encrypt_nopad(content)?; + Ok(()) + } + + #[inline] + pub fn decrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { + self.0.decrypt_nopad(content)?; + Ok(()) + } +} + + +/// Reusable encoder/decoder for Aes256 in Ctr mode and no padding +pub struct AesCtr256(Aes256Ctr); + +impl AesCtr256 { + + /// New encoder/decoder + #[inline] + pub fn new(key: &[u8], iv: &[u8]) -> Result { + Ok(AesCtr256( + Aes256Ctr::new(GenericArray::from_slice(key), GenericArray::from_slice(iv)) + )) + } + + #[inline] + pub fn encrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { + self.0.try_apply_keystream(content)?; + Ok(()) + } + + #[inline] + pub fn decrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { + self.0.try_apply_keystream(content)?; + Ok(()) + } +} /// Encrypt a message (CTR mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. +/// If possible please use `inplace_encrypt_128_ctr` to avoid a slice copy. pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?; + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + &mut dest[..plain.len()].copy_from_slice(plain); + encryptor.try_apply_keystream(dest)?; + Ok(()) + +} + +/// An error is returned if the input lengths are invalid. +pub fn inplace_encrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + encryptor.try_apply_keystream(data)?; Ok(()) + } /// Decrypt a message (CTR mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. +/// If possible please use `inplace_decrypt_128_ctr` instead. pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?; + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + + &mut dest[..encrypted.len()].copy_from_slice(encrypted); + encryptor.try_apply_keystream(dest)?; + Ok(()) +} + +/// Decrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn inplace_decrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + + encryptor.try_apply_keystream(data)?; Ok(()) } + +#[cfg(test)] +fn encrypt_128_cbc(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let encryptor = Cbc::::new_varkey(k, GenericArray::from_slice(iv))?; + &mut dest[..plain.len()].copy_from_slice(plain); + encryptor.encrypt_pad(dest, plain.len())?; + Ok(()) +} + + /// Decrypt a message (CBC mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { - let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); - let len = dest.len(); - let mut buffer = RefWriteBuffer::new(dest); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; - Ok(len - buffer.remaining()) + let encryptor = Cbc::::new_varkey(k, GenericArray::from_slice(iv))?; + &mut dest[..encrypted.len()].copy_from_slice(encrypted); + let unpad_length = { + encryptor.decrypt_pad(&mut dest[..encrypted.len()])?.len() + }; + Ok(unpad_length) +} + + +// retrocomptibility test +#[test] +pub fn test_aes_short() -> Result<(),SymmError> { + let key = include_bytes!("../test/key1"); + let salt = include_bytes!("../test/salt1"); + let content = include_bytes!("../test/content"); + let ctr_enc = include_bytes!("../test/result_128_ctr"); + let cbc_enc = include_bytes!("../test/result_128_cbc"); + let mut dest = vec![0;110]; + let mut dest_padded = vec![0;112]; + let mut dest_padded2 = vec![0;128]; // TODO RustLib need an extra 16bytes in dest : looks extra buggy but function is not currently use (keep it private for now) + encrypt_128_cbc(&key[..16], &salt[..16], content, &mut dest_padded2)?; + assert!(&dest_padded2[..112] == &cbc_enc[..]); + // buffer2.write_all(&dest1[..]).unwrap(); + encrypt_128_ctr(&key[..16], &salt[..16], content, &mut dest)?; + assert!(&dest[..] == &ctr_enc[..]); + let mut content_data = content.to_vec(); + inplace_encrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; + assert!(&content_data[..] == &ctr_enc[..]); + decrypt_128_ctr(&key[..16], &salt[..16], &ctr_enc[..], &mut dest)?; + assert!(&dest[..] == &content[..]); + let mut content_data = ctr_enc.to_vec(); + inplace_decrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; + assert!(&content_data[..] == &content[..]); + let l = decrypt_128_cbc(&key[..16], &salt[..16], &cbc_enc[..], &mut dest_padded)?; + assert!(&dest_padded[..l] == &content[..]); + Ok(()) } diff --git a/parity-crypto/src/digest.rs b/parity-crypto/src/digest.rs index b2be0b8ed..011746d83 100644 --- a/parity-crypto/src/digest.rs +++ b/parity-crypto/src/digest.rs @@ -14,17 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use rcrypto::ripemd160; +use rripemd160; use ring::digest::{self, Context, SHA256, SHA512}; use std::marker::PhantomData; use std::ops::Deref; +use rdigest::generic_array::GenericArray; +use rdigest::generic_array::typenum::U20; + /// The message digest. pub struct Digest(InnerDigest, PhantomData); enum InnerDigest { Ring(digest::Digest), - Ripemd160([u8; 20]), + Ripemd160(GenericArray), } impl Deref for Digest { @@ -63,7 +66,7 @@ pub struct Hasher(Inner, PhantomData); enum Inner { Ring(Context), - Ripemd160(ripemd160::Ripemd160) + Ripemd160(rripemd160::Ripemd160) } impl Hasher { @@ -80,7 +83,7 @@ impl Hasher { impl Hasher { pub fn ripemd160() -> Hasher { - Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData) + Hasher(Inner::Ripemd160(rripemd160::Ripemd160::default()), PhantomData) } } @@ -89,8 +92,8 @@ impl Hasher { match self.0 { Inner::Ring(ref mut ctx) => ctx.update(data), Inner::Ripemd160(ref mut ctx) => { - use rcrypto::digest::Digest; - ctx.input(data) + use rdigest::Input; + ctx.process(data) } } } @@ -98,11 +101,9 @@ impl Hasher { pub fn finish(self) -> Digest { match self.0 { Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData), - Inner::Ripemd160(mut ctx) => { - use rcrypto::digest::Digest; - let mut d = [0; 20]; - ctx.result(&mut d); - Digest(InnerDigest::Ripemd160(d), PhantomData) + Inner::Ripemd160(ctx) => { + use rdigest::Digest; + Digest(InnerDigest::Ripemd160(ctx.result()), PhantomData) } } } diff --git a/parity-crypto/src/error.rs b/parity-crypto/src/error.rs index 4e5582e19..f8554d14d 100644 --- a/parity-crypto/src/error.rs +++ b/parity-crypto/src/error.rs @@ -14,8 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use rcrypto; use ring; +use rscrypt; +use block_modes; +use raes; +use aes_ctr; quick_error! { #[derive(Debug)] @@ -42,16 +45,22 @@ quick_error! { InvalidP { display("Invalid p argument of the scrypt encryption") } + ScryptParam(e: rscrypt::errors::InvalidParams) { + display("invalid params for scrypt: {}", e) + cause(e) + from() + } + ScryptLength(e: rscrypt::errors::InvalidOutputLen) { + display("invalid scrypt output length: {}", e) + cause(e) + from() + } } } quick_error! { #[derive(Debug)] pub enum SymmError wraps PrivSymmErr { - RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) { - display("symmetric crypto error") - from() - } Ring(e: ring::error::Unspecified) { display("symmetric crypto error") cause(e) @@ -60,6 +69,18 @@ quick_error! { Offset(x: usize) { display("offset {} greater than slice length", x) } + BlockMode(e: block_modes::BlockModeError) { + display("symmetric crypto error") + from() + } + KeyStream(e: aes_ctr::stream_cipher::LoopError) { + display("ctr key stream ended") + from() + } + InvalidKeyLength(e: raes::block_cipher_trait::InvalidKeyLength) { + display("Error with RustCrypto key length : {}", e) + from() + } } } @@ -75,8 +96,20 @@ impl From for SymmError { } } -impl From for SymmError { - fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError { - SymmError(PrivSymmErr::RustCrypto(e)) +impl From for SymmError { + fn from(e: block_modes::BlockModeError) -> SymmError { + SymmError(PrivSymmErr::BlockMode(e)) + } +} + +impl From for SymmError { + fn from(e: raes::block_cipher_trait::InvalidKeyLength) -> SymmError { + SymmError(PrivSymmErr::InvalidKeyLength(e)) + } +} + +impl From for SymmError { + fn from(e: aes_ctr::stream_cipher::LoopError) -> SymmError { + SymmError(PrivSymmErr::KeyStream(e)) } } diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 1958067f9..7c3eb8083 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -16,12 +16,17 @@ //! Crypto utils used ethstore and network. -extern crate crypto as rcrypto; extern crate ethereum_types; #[macro_use] extern crate quick_error; extern crate ring; extern crate tiny_keccak; +extern crate scrypt as rscrypt; +extern crate ripemd160 as rripemd160; +extern crate digest as rdigest; +extern crate aes as raes; +extern crate aes_ctr; +extern crate block_modes; pub mod aes; pub mod aes_gcm; diff --git a/parity-crypto/src/scrypt.rs b/parity-crypto/src/scrypt.rs index 11c258155..7f869bfce 100644 --- a/parity-crypto/src/scrypt.rs +++ b/parity-crypto/src/scrypt.rs @@ -15,8 +15,10 @@ // along with Parity. If not, see . use error::ScryptError; -use rcrypto::scrypt::{scrypt, ScryptParams}; use super::{KEY_LENGTH_AES, KEY_LENGTH}; +use rscrypt:: {scrypt, ScryptParams}; +#[cfg(test)] +use std::io::{ Error }; pub fn derive_key(pass: &[u8], salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), ScryptError> { // sanity checks @@ -30,9 +32,32 @@ pub fn derive_key(pass: &[u8], salt: &[u8; 32], n: u32, p: u32, r: u32) -> Resul } let mut derived_key = vec![0u8; KEY_LENGTH]; - let scrypt_params = ScryptParams::new(log_n, r, p); - scrypt(pass, salt, &scrypt_params, &mut derived_key); + let scrypt_params = ScryptParams::new(log_n, r, p)?; + scrypt(pass, salt, &scrypt_params, &mut derived_key)?; let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) } + + +// test is build from previous crypto lib behaviour, values may be incorrect +// if previous crypto lib got a bug. +#[test] +pub fn test_derive() -> Result<(),Error> { + let pass = include_bytes!("../test/pass1"); + let salt_v = include_bytes!("../test/salt1"); + let mut salt = [0;32]; + salt.copy_from_slice(&salt_v[..32]); + let r1 = include_bytes!("../test/right1_1"); + let r2 = include_bytes!("../test/right1_2"); + let l1 = include_bytes!("../test/left1_1"); + let l2 = include_bytes!("../test/left1_2"); + + let (l,r) = derive_key(&pass[..],&salt, 262, 1, 8).unwrap(); + assert!(l == r1); + assert!(r == l1); + let (l,r) = derive_key(&pass[..],&salt, 144, 4, 4).unwrap(); + assert!(l == r2); + assert!(r == l2); + Ok(()) +} diff --git a/parity-crypto/test/content b/parity-crypto/test/content new file mode 100644 index 000000000..e3db0a16f --- /dev/null +++ b/parity-crypto/test/content @@ -0,0 +1,2 @@ +Some content to test aes, +not to much , only very basic test to avoid obvious regression when switching libs. diff --git a/parity-crypto/test/key1 b/parity-crypto/test/key1 new file mode 100644 index 000000000..af39cda5a --- /dev/null +++ b/parity-crypto/test/key1 @@ -0,0 +1 @@ +anycontenttoreach128bitsize diff --git a/parity-crypto/test/left1_1 b/parity-crypto/test/left1_1 new file mode 100644 index 000000000..bea4e8929 --- /dev/null +++ b/parity-crypto/test/left1_1 @@ -0,0 +1 @@ +Zw-Cc—QX¦Òô{Ð \ No newline at end of file diff --git a/parity-crypto/test/left1_2 b/parity-crypto/test/left1_2 new file mode 100644 index 000000000..0f7a880de --- /dev/null +++ b/parity-crypto/test/left1_2 @@ -0,0 +1 @@ +ý{„ ¼YÄkàï燱}> \ No newline at end of file diff --git a/parity-crypto/test/pass1 b/parity-crypto/test/pass1 new file mode 100644 index 000000000..1b104ed7b --- /dev/null +++ b/parity-crypto/test/pass1 @@ -0,0 +1 @@ +mypass diff --git a/parity-crypto/test/result_128_cbc b/parity-crypto/test/result_128_cbc new file mode 100644 index 0000000000000000000000000000000000000000..94d657dd1e9f369cd4c8dc6821636c07fff643fa GIT binary patch literal 112 zcmV-$0FVEt_yt-EjMs{#eThsj^S>~+_ia`fEm7A1Gu^p^Vd}l~|7+4lJSp8PiMggK zK@!N9>HolO8EJE&(SGY=!13`D`B(HDlDfTY3G;*mX*Hq<>r`viJDzdlc%m}xdq%rc SNs Date: Thu, 11 Oct 2018 12:03:21 +0200 Subject: [PATCH 02/39] Build to wasm32 (hmac and pbkdf2 will probably need to be implemented soon). --- parity-crypto/Cargo.toml | 6 ++++- parity-crypto/src/digest.rs | 46 +++++++++++++++++++++----------- parity-crypto/src/error.rs | 53 +++++++++++++++++++++++++++++++++++-- parity-crypto/src/lib.rs | 10 +++++++ 4 files changed, 97 insertions(+), 18 deletions(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 09e69d65b..fbe52b5a6 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -8,11 +8,15 @@ license = "GPL-3.0" [dependencies] quick-error = "1.2.2" -ring = "0.13" + tiny-keccak = "1.4" scrypt = { version = "0.1.1", default-features = false } ripemd160 = "0.7.0" +sha2 = "0.7.0" digest = "0.7" aes = "0.2.0" aes-ctr = "0.1.0" block-modes = "0.1.0" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +ring = "0.13" diff --git a/parity-crypto/src/digest.rs b/parity-crypto/src/digest.rs index 011746d83..ce0e46254 100644 --- a/parity-crypto/src/digest.rs +++ b/parity-crypto/src/digest.rs @@ -15,18 +15,20 @@ // along with Parity. If not, see . use rripemd160; -use ring::digest::{self, Context, SHA256, SHA512}; +use rsha2; use std::marker::PhantomData; use std::ops::Deref; use rdigest::generic_array::GenericArray; -use rdigest::generic_array::typenum::U20; - +use rdigest::generic_array::typenum::{U20, U32, U64}; +use rdigest::Input; +use rsha2::Digest as RDigest; /// The message digest. pub struct Digest(InnerDigest, PhantomData); enum InnerDigest { - Ring(digest::Digest), + Sha256(GenericArray), + Sha512(GenericArray), Ripemd160(GenericArray), } @@ -34,20 +36,25 @@ impl Deref for Digest { type Target = [u8]; fn deref(&self) -> &Self::Target { match self.0 { - InnerDigest::Ring(ref d) => d.as_ref(), - InnerDigest::Ripemd160(ref d) => &d[..] + InnerDigest::Sha256(ref d) => &d[..], + InnerDigest::Sha512(ref d) => &d[..], + InnerDigest::Ripemd160(ref d) => &d[..], } } } /// Single-step sha256 digest computation. pub fn sha256(data: &[u8]) -> Digest { - Digest(InnerDigest::Ring(digest::digest(&SHA256, data)), PhantomData) + let mut hasher = Hasher::sha256(); + hasher.update(data); + hasher.finish() } /// Single-step sha512 digest computation. pub fn sha512(data: &[u8]) -> Digest { - Digest(InnerDigest::Ring(digest::digest(&SHA512, data)), PhantomData) + let mut hasher = Hasher::sha512(); + hasher.update(data); + hasher.finish() } /// Single-step ripemd160 digest computation. @@ -65,19 +72,20 @@ pub enum Ripemd160 {} pub struct Hasher(Inner, PhantomData); enum Inner { - Ring(Context), + Sha256(rsha2::Sha256), + Sha512(rsha2::Sha512), Ripemd160(rripemd160::Ripemd160) } impl Hasher { pub fn sha256() -> Hasher { - Hasher(Inner::Ring(Context::new(&SHA256)), PhantomData) + Hasher(Inner::Sha256(rsha2::Sha256::default()), PhantomData) } } impl Hasher { pub fn sha512() -> Hasher { - Hasher(Inner::Ring(Context::new(&SHA512)), PhantomData) + Hasher(Inner::Sha512(rsha2::Sha512::default()), PhantomData) } } @@ -90,9 +98,13 @@ impl Hasher { impl Hasher { pub fn update(&mut self, data: &[u8]) { match self.0 { - Inner::Ring(ref mut ctx) => ctx.update(data), + Inner::Sha256(ref mut ctx) => { + ctx.process(data) + }, + Inner::Sha512(ref mut ctx) => { + ctx.process(data) + }, Inner::Ripemd160(ref mut ctx) => { - use rdigest::Input; ctx.process(data) } } @@ -100,9 +112,13 @@ impl Hasher { pub fn finish(self) -> Digest { match self.0 { - Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData), + Inner::Sha256(ctx) => { + Digest(InnerDigest::Sha256(ctx.result()), PhantomData) + }, + Inner::Sha512(ctx) => { + Digest(InnerDigest::Sha512(ctx.result()), PhantomData) + }, Inner::Ripemd160(ctx) => { - use rdigest::Digest; Digest(InnerDigest::Ripemd160(ctx.result()), PhantomData) } } diff --git a/parity-crypto/src/error.rs b/parity-crypto/src/error.rs index f8554d14d..42d42fa71 100644 --- a/parity-crypto/src/error.rs +++ b/parity-crypto/src/error.rs @@ -14,12 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +#[cfg(not(target_arch = "wasm32"))] use ring; use rscrypt; use block_modes; use raes; use aes_ctr; + + quick_error! { #[derive(Debug)] pub enum Error { @@ -58,14 +61,52 @@ quick_error! { } } +/* +#[cfg(not(target_arch = "wasm32"))] +macro_rules! ring_error { + () => { + Ring(e: ring::error::Unspecified) { + display("symmetric crypto error") + cause(e) + from() + } + }; +} + +#[cfg(target_arch = "wasm32")] +macro_rules! ring_error { + () => { + }; +} +*/ + + +#[cfg(target_arch = "wasm32")] quick_error! { #[derive(Debug)] pub enum SymmError wraps PrivSymmErr { - Ring(e: ring::error::Unspecified) { + Offset(x: usize) { + display("offset {} greater than slice length", x) + } + BlockMode(e: block_modes::BlockModeError) { display("symmetric crypto error") - cause(e) from() } + KeyStream(e: aes_ctr::stream_cipher::LoopError) { + display("ctr key stream ended") + from() + } + InvalidKeyLength(e: raes::block_cipher_trait::InvalidKeyLength) { + display("Error with RustCrypto key length : {}", e) + from() + } + } +} + +#[cfg(not(target_arch = "wasm32"))] +quick_error! { + #[derive(Debug)] + pub enum SymmError wraps PrivSymmErr { Offset(x: usize) { display("offset {} greater than slice length", x) } @@ -81,15 +122,23 @@ quick_error! { display("Error with RustCrypto key length : {}", e) from() } + Ring(e: ring::error::Unspecified) { + display("symmetric crypto error") + cause(e) + from() + } } } + +#[cfg(not(target_arch = "wasm32"))] impl SymmError { pub(crate) fn offset_error(x: usize) -> SymmError { SymmError(PrivSymmErr::Offset(x)) } } +#[cfg(not(target_arch = "wasm32"))] impl From for SymmError { fn from(e: ring::error::Unspecified) -> SymmError { SymmError(PrivSymmErr::Ring(e)) diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index ae376c0e3..7b0d1e405 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -18,22 +18,30 @@ #[macro_use] extern crate quick_error; +#[cfg(not(target_arch = "wasm32"))] extern crate ring; extern crate tiny_keccak; extern crate scrypt as rscrypt; extern crate ripemd160 as rripemd160; +extern crate sha2 as rsha2; extern crate digest as rdigest; extern crate aes as raes; extern crate aes_ctr; extern crate block_modes; pub mod aes; +#[cfg(not(target_arch = "wasm32"))] pub mod aes_gcm; +// could create a less safe RustCrypto based aes_gcm here if needed for wasm pub mod error; pub mod scrypt; pub mod digest; +#[cfg(not(target_arch = "wasm32"))] pub mod hmac; +// could create a less safe crate using RustCrypto or just switch +#[cfg(not(target_arch = "wasm32"))] pub mod pbkdf2; +// could create a less safe crate using RustCrypto or just switch pub use error::Error; @@ -60,6 +68,7 @@ impl Keccak256<[u8; 32]> for T where T: AsRef<[u8]> { } } +#[cfg(not(target_arch = "wasm32"))] pub fn derive_key_iterations(password: &[u8], salt: &[u8], c: u32) -> (Vec, Vec) { let mut derived_key = [0u8; KEY_LENGTH]; pbkdf2::sha256(c, pbkdf2::Salt(salt), pbkdf2::Secret(password), &mut derived_key); @@ -75,6 +84,7 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { mac } +#[cfg(not(target_arch = "wasm32"))] pub fn is_equal(a: &[u8], b: &[u8]) -> bool { ring::constant_time::verify_slices_are_equal(a, b).is_ok() } From c20f544c76a9a00a2d6d1d4753f1ed22b6c30ebd Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 11 Oct 2018 12:10:17 +0200 Subject: [PATCH 03/39] temp use of previous ring version --- parity-crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index fbe52b5a6..da5f85bee 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -19,4 +19,4 @@ aes-ctr = "0.1.0" block-modes = "0.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -ring = "0.13" +ring = "0.12" From c19caa55801dc77519b8a03af81454c835ac3317 Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 15 Oct 2018 18:36:53 +0200 Subject: [PATCH 04/39] Alternate hmac impl --- parity-crypto/Cargo.toml | 12 +++- parity-crypto/src/digest.rs | 7 +-- parity-crypto/src/hmac.rs | 29 +++++++++ parity-crypto/src/hmac_alt.rs | 111 ++++++++++++++++++++++++++++++++++ parity-crypto/src/lib.rs | 6 ++ 5 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 parity-crypto/src/hmac_alt.rs diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index da5f85bee..f6962d04b 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -11,12 +11,18 @@ quick-error = "1.2.2" tiny-keccak = "1.4" scrypt = { version = "0.1.1", default-features = false } -ripemd160 = "0.7.0" -sha2 = "0.7.0" -digest = "0.7" +ripemd160 = "0.8.0" +sha2 = "0.8.0" +digest = "0.8" aes = "0.2.0" aes-ctr = "0.1.0" block-modes = "0.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.12" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +hmac = "0.7" + +[dev-dependencies] +hmac = "0.7" diff --git a/parity-crypto/src/digest.rs b/parity-crypto/src/digest.rs index ce0e46254..40bafe145 100644 --- a/parity-crypto/src/digest.rs +++ b/parity-crypto/src/digest.rs @@ -20,7 +20,6 @@ use std::marker::PhantomData; use std::ops::Deref; use rdigest::generic_array::GenericArray; use rdigest::generic_array::typenum::{U20, U32, U64}; -use rdigest::Input; use rsha2::Digest as RDigest; /// The message digest. @@ -99,13 +98,13 @@ impl Hasher { pub fn update(&mut self, data: &[u8]) { match self.0 { Inner::Sha256(ref mut ctx) => { - ctx.process(data) + ctx.input(data) }, Inner::Sha512(ref mut ctx) => { - ctx.process(data) + ctx.input(data) }, Inner::Ripemd160(ref mut ctx) => { - ctx.process(data) + ctx.input(data) } } } diff --git a/parity-crypto/src/hmac.rs b/parity-crypto/src/hmac.rs index ff337ed02..9794bcfbc 100644 --- a/parity-crypto/src/hmac.rs +++ b/parity-crypto/src/hmac.rs @@ -86,3 +86,32 @@ impl VerifyKey { pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { hmac::verify(&k.0, data, sig).is_ok() } + + + +#[test] +fn simple_mac_and_verify() { + let input = b"Some bytes"; + let big_input = vec![7u8;2000]; + + let key1 = vec![3u8;64]; + let key2 = vec![4u8;128]; + + let sig_key1 = SigKey::sha256(&key1[..]); + let sig_key2 = SigKey::sha512(&key2[..]); + + let mut signer1 = Signer::with(&sig_key1); + let mut signer2 = Signer::with(&sig_key2); + + signer1.update(&input[..]); + for i in 0 .. big_input.len() / 33 { + signer2.update(&big_input[i*33..(i+1)*33]); + } + signer2.update(&big_input[(big_input.len() / 33)*33..]); + let sig1 = signer1.sign(); + assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); + let sig2 = signer2.sign(); + assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); + assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); + assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); +} diff --git a/parity-crypto/src/hmac_alt.rs b/parity-crypto/src/hmac_alt.rs new file mode 100644 index 000000000..fddf08003 --- /dev/null +++ b/parity-crypto/src/hmac_alt.rs @@ -0,0 +1,111 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . +extern crate hmac; +use rdigest::generic_array::{GenericArray}; +use rsha2::Sha256; +use rsha2::Sha512; +use std::marker::PhantomData; +use std::ops::Deref; +use self::hmac::{Hmac, Mac}; + +/// HMAC signature. Note the public interface of this module is a bit awkward for RustCrypto. +pub struct Signature(GenericArray, PhantomData); + +impl Deref for Signature { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + &self.0[..] + } +} + +/// HMAC signing key. +pub struct SigKey(GenericArray, PhantomData); + +impl SigKey> { + pub fn sha256(key: &[u8]) -> SigKey> { + SigKey(GenericArray::clone_from_slice(key), PhantomData) + } +} + +impl SigKey> { + pub fn sha512(key: &[u8]) -> SigKey> { + SigKey(GenericArray::clone_from_slice(key), PhantomData) + } +} + + +/// Compute HMAC signature of `data`. +/// TODO consider removal of this method in favor of all stateful +pub fn sign(k: &SigKey, data: &[u8]) -> Signature { + let mut sig = Signer::with(k); + sig.update(data); + sig.sign() +} + +/// Stateful HMAC computation. +pub struct Signer(T); + + +impl Signer { + pub fn with(key: &SigKey) -> Signer { + Signer(T::new(&key.0)) + } + + pub fn update(&mut self, data: &[u8]) { + self.0.input(data) + } + + pub fn sign(mut self) -> Signature { + Signature(self.0.result_reset().code(), PhantomData) + } +} + +/// HMAC signature verification key. +pub type VerifyKey = SigKey; + +/// Verify HMAC signature of `data`. +pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { + let mut ver = Signer::with(k); + ver.update(data); + ver.0.verify(sig).is_ok() +} + +#[test] +fn simple_mac_and_verify() { + let input = b"Some bytes"; + let big_input = vec![7u8;2000]; + + let key1 = vec![3u8;64]; + let key2 = vec![4u8;128]; + + let sig_key1 = SigKey::sha256(&key1[..]); + let sig_key2 = SigKey::sha512(&key2[..]); + let mut signer1 = Signer::with(&sig_key1); + let mut signer2 = Signer::with(&sig_key2); + + signer1.update(&input[..]); + for i in 0 .. big_input.len() / 33 { + signer2.update(&big_input[i*33..(i+1)*33]); + } + signer2.update(&big_input[(big_input.len() / 33)*33..]); + let sig1 = signer1.sign(); + assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); + let sig2 = signer2.sign(); + assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); + + assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); + assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); +} diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 7b0d1e405..a24192b5a 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -38,6 +38,12 @@ pub mod scrypt; pub mod digest; #[cfg(not(target_arch = "wasm32"))] pub mod hmac; +#[cfg(all(not(target_arch = "wasm32"), test))] +pub mod hmac_alt; +#[path = "hmac_alt.rs"] +#[cfg(target_arch = "wasm32")] +pub mod hmac; + // could create a less safe crate using RustCrypto or just switch #[cfg(not(target_arch = "wasm32"))] pub mod pbkdf2; From 2da14e47444fc083a1cae1b5bb7b5827b3d6db87 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 16 Oct 2018 11:36:22 +0200 Subject: [PATCH 05/39] hmac verify in test and is_equal method --- parity-crypto/Cargo.toml | 1 + parity-crypto/src/hmac.rs | 5 +++++ parity-crypto/src/hmac_alt.rs | 11 +++++++++-- parity-crypto/src/lib.rs | 10 ++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index f6962d04b..90e4d874d 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -23,6 +23,7 @@ ring = "0.12" [target.'cfg(target_arch = "wasm32")'.dependencies] hmac = "0.7" +subtle = "1.0" [dev-dependencies] hmac = "0.7" diff --git a/parity-crypto/src/hmac.rs b/parity-crypto/src/hmac.rs index 9794bcfbc..6883040d2 100644 --- a/parity-crypto/src/hmac.rs +++ b/parity-crypto/src/hmac.rs @@ -114,4 +114,9 @@ fn simple_mac_and_verify() { assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); + let verif_key1 = VerifyKey::sha256(&key1[..]); + let verif_key2 = VerifyKey::sha512(&key2[..]); + assert!(verify(&verif_key1, &input[..], &sig1[..])); + assert!(verify(&verif_key2, &big_input[..], &sig2[..])); + } diff --git a/parity-crypto/src/hmac_alt.rs b/parity-crypto/src/hmac_alt.rs index fddf08003..cb5b1a563 100644 --- a/parity-crypto/src/hmac_alt.rs +++ b/parity-crypto/src/hmac_alt.rs @@ -85,6 +85,7 @@ pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { #[test] fn simple_mac_and_verify() { + use super::is_equal; let input = b"Some bytes"; let big_input = vec![7u8;2000]; @@ -104,8 +105,14 @@ fn simple_mac_and_verify() { let sig1 = signer1.sign(); assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); let sig2 = signer2.sign(); - assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); + assert!(is_equal(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..])); - assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); + assert!(is_equal(&sig1[..], &sign(&sig_key1, &input[..])[..])); assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); + let verif_key1 = VerifyKey::sha256(&key1[..]); + let verif_key2 = VerifyKey::sha512(&key2[..]); + assert!(verify(&verif_key1, &input[..], &sig1[..])); + assert!(verify(&verif_key2, &big_input[..], &sig2[..])); + + } diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index a24192b5a..28564dcf7 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -20,6 +20,8 @@ extern crate quick_error; #[cfg(not(target_arch = "wasm32"))] extern crate ring; +#[cfg(target_arch = "wasm32")] +extern crate subtle; extern crate tiny_keccak; extern crate scrypt as rscrypt; extern crate ripemd160 as rripemd160; @@ -94,3 +96,11 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { pub fn is_equal(a: &[u8], b: &[u8]) -> bool { ring::constant_time::verify_slices_are_equal(a, b).is_ok() } + +#[cfg(target_arch = "wasm32")] +pub fn is_equal(a: &[u8], b: &[u8]) -> bool { + use subtle::ConstantTimeEq; + a.ct_eq(b).unwrap_u8() == 1 +} + + From 41d4c783ecaca1d1432e1273815c2ff712fa4f1c Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 16 Oct 2018 18:33:36 +0200 Subject: [PATCH 06/39] In progress of moving secp256k1 in crypto --- parity-crypto/Cargo.toml | 6 +++ parity-crypto/src/lib.rs | 16 ++++++ parity-crypto/src/secp256k1.rs | 86 ++++++++++++++++++++++++++++++ parity-crypto/src/secp256k1_alt.rs | 27 ++++++++++ 4 files changed, 135 insertions(+) create mode 100644 parity-crypto/src/secp256k1.rs create mode 100644 parity-crypto/src/secp256k1_alt.rs diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 90e4d874d..c3003eeb9 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["rename-dependency"] + [package] name = "parity-crypto" version = "0.2.0" @@ -20,10 +22,14 @@ block-modes = "0.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.12" +eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } +lazy_static = "1.0" # for this secp [target.'cfg(target_arch = "wasm32")'.dependencies] hmac = "0.7" subtle = "1.0" +libsecp256k1 = { version = "0.1", package = "libsecp256k1" } [dev-dependencies] hmac = "0.7" +libsecp256k1 = { version = "0.1", package = "libsecp256k1" } diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 28564dcf7..a19627ffc 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -31,6 +31,12 @@ extern crate aes as raes; extern crate aes_ctr; extern crate block_modes; + + +#[cfg(not(target_arch = "wasm32"))] +#[macro_use] extern crate lazy_static; + + pub mod aes; #[cfg(not(target_arch = "wasm32"))] pub mod aes_gcm; @@ -46,6 +52,16 @@ pub mod hmac_alt; #[cfg(target_arch = "wasm32")] pub mod hmac; + +#[cfg(not(target_arch = "wasm32"))] +pub mod secp256k1; + +#[cfg(all(not(target_arch = "wasm32"), test))] +pub mod secp256k1_alt; +#[path = "secp256k1_alt.rs"] +#[cfg(target_arch = "wasm32")] +pub mod secp256k1; + // could create a less safe crate using RustCrypto or just switch #[cfg(not(target_arch = "wasm32"))] pub mod pbkdf2; diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs new file mode 100644 index 000000000..e472760af --- /dev/null +++ b/parity-crypto/src/secp256k1.rs @@ -0,0 +1,86 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! secp256k1 for parity. +//! TODO sized u8 array in proto should be usable if we add methods such as U256 -> &[u8;32] to ethereum_types + +extern crate secp256k1; + +// reexports +pub use self::secp256k1::{ + Error, + Secp256k1, + ecdh, +}; + +pub use self::secp256k1::key::{SecretKey, PublicKey, MINUS_ONE_KEY, ONE_KEY}; +pub use self::secp256k1::constants::{SECRET_KEY_SIZE, GENERATOR_X, GENERATOR_Y, CURVE_ORDER}; + +use self::secp256k1::{ + Message, + RecoverableSignature, + RecoveryId, +}; + +lazy_static! { + pub static ref SECP256K1: self::secp256k1::Secp256k1 = self::secp256k1::Secp256k1::new(); +} + + +pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { + let context = &SECP256K1; + let sec = SecretKey::from_slice(context, &secret[..])?; + let s = context.sign_recoverable(&Message::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(data_arr) +} + +pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { + let context = &SECP256K1; + let rsig = RecoverableSignature::from_compact(context, &signature[0..64], 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); + temp + }; + + let publ = PublicKey::from_slice(context, &pdata)?; + match context.verify(&Message::from_slice(message)?, &sig, &publ) { + Ok(_) => Ok(true), + Err(Error::IncorrectSignature) => Ok(false), + Err(x) => Err(Error::from(x)) + } +} + +pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { + let context = &SECP256K1; + let rsig = RecoverableSignature::from_compact(context, &signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; + let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; + let serialized = pubkey.serialize_vec(context, false); + + let mut res = [0;64]; + res.copy_from_slice(&serialized[1..65]); + Ok(res) +} + + diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs new file mode 100644 index 000000000..fd2033b79 --- /dev/null +++ b/parity-crypto/src/secp256k1_alt.rs @@ -0,0 +1,27 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! secp256k1 for parity. + +extern crate libsecp256k1 as secp256k1; + +pub use self::secp256k1::{ + Message, + RecoveryId, + Error, + PublicKey, + SecretKey, +}; From 0083acfcad52d3e3abe2aa483ca5328fc609493f Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 18 Oct 2018 11:39:13 +0200 Subject: [PATCH 07/39] Add basic (type and proto are currently bad and should probably move to something in a trait to factor tests) secp256k1, derived from parity ethereum usage. Add an alternate implementation that compiles to wasm32 (from sorpass secp crate). --- parity-crypto/Cargo.toml | 6 +- parity-crypto/src/lib.rs | 7 +- parity-crypto/src/secp256k1.rs | 238 +++++++++++++++++- parity-crypto/src/secp256k1_alt.rs | 372 ++++++++++++++++++++++++++++- 4 files changed, 602 insertions(+), 21 deletions(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index c3003eeb9..fc291381f 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -19,17 +19,19 @@ digest = "0.8" aes = "0.2.0" aes-ctr = "0.1.0" block-modes = "0.1.0" +rand = "0.4" +lazy_static = "1.0" # for secp [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.12" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } -lazy_static = "1.0" # for this secp [target.'cfg(target_arch = "wasm32")'.dependencies] hmac = "0.7" -subtle = "1.0" +subtle = { version = "1.0", features = ["nightly"] } libsecp256k1 = { version = "0.1", package = "libsecp256k1" } [dev-dependencies] hmac = "0.7" libsecp256k1 = { version = "0.1", package = "libsecp256k1" } + diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index a19627ffc..1704a8258 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -18,6 +18,8 @@ #[macro_use] extern crate quick_error; +#[macro_use] +extern crate lazy_static; #[cfg(not(target_arch = "wasm32"))] extern crate ring; #[cfg(target_arch = "wasm32")] @@ -32,11 +34,6 @@ extern crate aes_ctr; extern crate block_modes; - -#[cfg(not(target_arch = "wasm32"))] -#[macro_use] extern crate lazy_static; - - pub mod aes; #[cfg(not(target_arch = "wasm32"))] pub mod aes_gcm; diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index e472760af..0f7ef94a1 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -16,29 +16,43 @@ //! secp256k1 for parity. //! TODO sized u8 array in proto should be usable if we add methods such as U256 -> &[u8;32] to ethereum_types +//! TODO use SecretKey and PublicKey explicitly in if (with conversion from &[u8]) : methods are +//! highly inefficient here. extern crate secp256k1; +extern crate rand; + +use self::rand::Rng; // reexports pub use self::secp256k1::{ - Error, - Secp256k1, - ecdh, + Error, }; -pub use self::secp256k1::key::{SecretKey, PublicKey, MINUS_ONE_KEY, ONE_KEY}; +pub use self::secp256k1::key::{SecretKey, PublicKey}; pub use self::secp256k1::constants::{SECRET_KEY_SIZE, GENERATOR_X, GENERATOR_Y, CURVE_ORDER}; +use self::secp256k1::key::{ONE_KEY, MINUS_ONE_KEY}; use self::secp256k1::{ - Message, - RecoverableSignature, - RecoveryId, + Message, + RecoverableSignature, + RecoveryId, + ecdh, }; lazy_static! { pub static ref SECP256K1: self::secp256k1::Secp256k1 = self::secp256k1::Secp256k1::new(); } +pub fn one_key() -> &'static SecretKey { + &ONE_KEY +} + +pub fn minus_one_key() -> &'static SecretKey { + &MINUS_ONE_KEY +} + + pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { let context = &SECP256K1; @@ -53,6 +67,8 @@ pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { Ok(data_arr) } +/// TODO use public as 65 instead ?? (here it is 64 but serialize as 65 usually) -> at least put a +/// big doc about that!! pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; let rsig = RecoverableSignature::from_compact(context, &signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; @@ -78,9 +94,213 @@ pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; let serialized = pubkey.serialize_vec(context, false); - let mut res = [0;64]; - res.copy_from_slice(&serialized[1..65]); + let mut res = [0;64]; + res.copy_from_slice(&serialized[1..65]); Ok(res) } +pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { + SECP256K1.generate_keypair(r) + .expect("context always created with full capabilities; qed") +} + +// TODO change it to slicable u8 return type +// Plus add comment explaining first bit removal +/// warning this returns 64 byte vec (we skip the first byte of 65 byte more standard +/// representation) +pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { + let mut a_vec = p.serialize_vec(&SECP256K1, false); + // &a_vec[1..65] + let _ = a_vec.drain(65..); + a_vec.remove(0); + a_vec +} + +/// only for test (or make the result erasable) +#[cfg(test)] +pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { + p[..].to_vec() +} + +pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { + p.serialize_vec(&SECP256K1, true) +} + +pub fn secret_from_slice(secret: &[u8]) -> Result { + SecretKey::from_slice(&SECP256K1, secret) +} + +pub struct SharedSecretAsRef(pub ecdh::SharedSecret); + +impl AsRef<[u8]> for SharedSecretAsRef { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +pub fn shared_secret(publ: &PublicKey, sec: &SecretKey) -> Result, Error> { + let shared = ecdh::SharedSecret::new_raw(&SECP256K1, &publ, &sec); + Ok(SharedSecretAsRef(shared)) +} + +/// using a shortened 64bit public key as input +pub fn public_from_slice(public_sec_raw: &[u8]) -> Result { + let pdata = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(&public_sec_raw[0..64]); + temp + }; + + PublicKey::from_slice(&SECP256K1, &pdata) +} + +pub fn public_from_secret(s: &SecretKey) -> Result { + PublicKey::from_secret_key(&SECP256K1, &s) +} + +pub fn public_mul(mut pub_key: PublicKey, sec_key: &SecretKey) -> Result { + pub_key.mul_assign(&SECP256K1, sec_key)?; + Ok(pub_key) +} + +pub fn public_add(mut pub_key: PublicKey, other_public: &PublicKey) -> Result { + pub_key.add_assign(&SECP256K1, other_public)?; + Ok(pub_key) +} + +pub fn secret_mul(mut sec_key: SecretKey, other_secret: &SecretKey) -> Result { + sec_key.mul_assign(&SECP256K1, other_secret)?; + Ok(sec_key) +} + +pub fn secret_add(mut sec_key: SecretKey, other_secret: &SecretKey) -> Result { + sec_key.add_assign(&SECP256K1, other_secret)?; + Ok(sec_key) +} + +pub fn secret_inv(mut sec_key: SecretKey) -> Result { + sec_key.inv_assign(&SECP256K1)?; + Ok(sec_key) +} + + + + +#[cfg(test)] +mod tests { + extern crate rand; + use super::{ + sign, + secret_from_slice, + verify_public, + recover, + generate_keypair, + public_to_vec, + secret_to_vec, + public_add, + public_from_slice, + public_mul, + minus_one_key, + secret_mul, + secret_inv, + one_key, + }; + use self::rand::OsRng; + + #[test] + fn sign_val() { + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let message = vec![2;32]; + let signature = sign(&sk[..], &message).unwrap(); + assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); + } + + #[test] + fn sign_and_recover_public() { + let mut osrng = OsRng::new().expect("test"); + let (secret, public) = generate_keypair(&mut osrng); + let message = vec![2;32]; + let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); + assert_eq!(&public_to_vec(&public).as_ref()[..], &recover(&signature, &message).unwrap()[..]); + } + + #[test] + fn sign_and_verify_public() { + let mut osrng = OsRng::new().expect("test"); + let (secret, public) = generate_keypair(&mut osrng); + let message = vec![0;32]; + let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); + assert!(verify_public(&public_to_vec(&public).as_ref()[..], &signature, &message).unwrap()); + } + + #[test] + fn public_addition() { + let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; + let pub1 = public_from_slice(&pk1[..]).unwrap(); + let pub2 = public_from_slice(&pk2[..]).unwrap(); + let res = public_add(pub1, &pub2).unwrap(); + + assert_eq!(&public_to_vec(&res).as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + } + + #[test] + fn public_multiplication() { + let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let pubk = public_from_slice(&pk[..]).unwrap(); + let sec = secret_from_slice(&sk[..]).unwrap(); + let res = public_mul(pubk, &sec).unwrap(); + + assert_eq!(&public_to_vec(&res).as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + } + + + #[test] + fn public_addition_is_commutative() { + let mut osrng = OsRng::new().expect("test"); + let (_, public1) = generate_keypair(&mut osrng); + let (_, public2) = generate_keypair(&mut osrng); + + let left = public_add(public1.clone(), &public2).unwrap(); + + let right = public_add(public2.clone(), &public1).unwrap(); + + assert_eq!(left, right); + } + + #[test] + fn public_addition_is_reversible_with_subtraction() { + let mut osrng = OsRng::new().expect("test"); + let (_, public1) = generate_keypair(&mut osrng); + let (_, public2) = generate_keypair(&mut osrng); + + let sum = public_add(public1.clone(), &public2).unwrap(); + let op = public_mul(public2.clone(), minus_one_key()).unwrap(); + let sum = public_add(sum, &op).unwrap(); + + assert_eq!(sum, public1); + } + + + #[test] + fn multiplicating_secret_inversion_with_secret_gives_one() { + let mut osrng = OsRng::new().expect("test"); + let (secret, _) = generate_keypair(&mut osrng); + let inversion = secret_inv(secret.clone()).unwrap(); + let inversion = secret_mul(inversion, &secret).unwrap(); + assert_eq!(inversion, *one_key()); + } + + #[test] + fn secret_inversion_is_reversible_with_inversion() { + let mut osrng = OsRng::new().expect("test"); + let (secret, _) = generate_keypair(&mut osrng); + let inversion = secret_inv(secret.clone()).unwrap(); + let inversion = secret_inv(inversion).unwrap(); + assert_eq!(inversion, secret); + } + +} + diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index fd2033b79..d46db0409 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -17,11 +17,373 @@ //! secp256k1 for parity. extern crate libsecp256k1 as secp256k1; +extern crate rand; + +use self::rand::Rng; + pub use self::secp256k1::{ - Message, - RecoveryId, - Error, - PublicKey, - SecretKey, + Error, + PublicKey, + SecretKey, +}; + + +use self::secp256k1::{ + Message, + Signature, + RecoveryId, }; + +use self::secp256k1::curve::{ + Affine, + Jacobian, + Scalar, +}; + +use self::secp256k1::curve::ECMULT_CONTEXT; + +pub const SECRET_KEY_SIZE: usize = 32; + +const MINUS_ONE_BYTES: [u8;32] = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 186, 174, 220, 230, 175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 64]; + +const ONE_BYTES: [u8;32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + + +/// The X coordinate of the generator (could get from lib AFFINE_G const but it is more convenient +/// this way : could be default value of a trait) +pub const GENERATOR_X: [u8; 32] = [ + 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, + 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, + 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, + 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98 +]; + +/// The Y coordinate of the generator +pub const GENERATOR_Y: [u8; 32] = [ + 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, + 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, + 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, + 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8 +]; + +/// The order of the secp256k1 curve +pub const CURVE_ORDER: [u8; 32] = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 +]; + +lazy_static! { + static ref MINUS_ONE_KEY: SecretKey = SecretKey::parse(&MINUS_ONE_BYTES).expect("static; qed"); + static ref ONE_KEY: SecretKey = SecretKey::parse(&ONE_BYTES).expect("static; qed"); +} + +pub fn one_key() -> &'static SecretKey { + &ONE_KEY +} + +pub fn minus_one_key() -> &'static SecretKey { + &MINUS_ONE_KEY +} + + +/// secret size 32, message size 32 +pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { + let mut buf = [0;32]; + buf.copy_from_slice(&message[..]); // panic on incorrect message size + let message = Message::parse(&buf); + buf.copy_from_slice(&secret[..]); // panic on incorrect secret size + let seckey = SecretKey::parse(&buf)?; + let (sig, rec_id) = secp256k1::sign(&message, &seckey)?; + let mut data_arr = [0; 65]; + + data_arr[0..64].copy_from_slice(&sig.serialize()); + data_arr[64] = rec_id.serialize(); + Ok(data_arr) +} + +/// public size 65, signature size 65, message size 32 +pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { + + let mut buf = [0;32]; + buf.copy_from_slice(&message[..]); // panic on incorrect message size + let message = Message::parse(&buf); + let mut buf = [4;65]; + buf[1..65].copy_from_slice(&public[..]); // panic on incorrect public size + let pubkey = PublicKey::parse(&buf)?; + + let mut buf = [0;64]; + buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size + let signature = Signature::parse(&buf); + + Ok(secp256k1::verify(&message, &signature, &pubkey)) +} + +/// signature 65, message 32, return publickey 64 bit (no start 4) +pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { + let mut buf = [0;32]; + buf.copy_from_slice(&message[..]); // panic on incorrect message size + let message = Message::parse(&buf); + let mut buf = [0;64]; + buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size + let recovery_id = RecoveryId::parse(signature[64])?; + let signature = Signature::parse(&buf); + let public_key = secp256k1::recover(&message, &signature, &recovery_id)?; + + let mut res = [0;64]; + res.copy_from_slice(&public_key.serialize()[1..65]); + + Ok(res) +} + +pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { + let secret_key = SecretKey::random(r); + let public_key = PublicKey::from_secret_key(&secret_key); + (secret_key, public_key) +} + +/// warning this returns 64 byte vec (we skip the first byte of 65 byte more standard +/// representation) +pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { + let a_vec = p.serialize(); + a_vec[1..65].to_vec() +} + +/// ret size 33 +pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { + p.serialize_compressed().to_vec() +} + +/// only for test (or make the result erasable) +#[cfg(test)] +pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { + p.serialize() +} + +/// 32 sized slice +pub fn secret_from_slice(secret: &[u8]) -> Result { + let mut buf = [0;32]; + buf.copy_from_slice(&secret[..]); // panic on incorrect secret size + SecretKey::parse(&buf) +} + +pub fn shared_secret(publ: &PublicKey, sec: &SecretKey) -> Result, Error> { + secp256k1::SharedSecret::new(publ, sec) +} + +/// using a shortened 64bit public key as input +pub fn public_from_slice(public_sec_raw: &[u8]) -> Result { + let mut buf = [4;65]; + buf[1..65].copy_from_slice(&public_sec_raw[..]); // panic on incorrect public size + PublicKey::parse(&buf) +} + +pub fn public_from_secret(s: &SecretKey) -> Result { + Ok(PublicKey::from_secret_key(&s)) +} + + +fn aff_to_public(aff_pub: &mut Affine) -> Result { + let mut buff = [4;65]; + let mut buff2 = [0;32]; + aff_pub.x.normalize(); + aff_pub.x.fill_b32(&mut buff2); + buff[1..33].copy_from_slice(&buff2[..]); + aff_pub.y.normalize(); + aff_pub.y.fill_b32(&mut buff2); + buff[33..65].copy_from_slice(&buff2[..]); + PublicKey::parse(&buff) + +} +pub fn public_add(pub_key: PublicKey, other_public: &PublicKey) -> Result { + let mut aff_pub: Affine = pub_key.into(); + let mut aff_pub_j = Jacobian::default(); + aff_pub_j.set_ge(&aff_pub); + let aff_pub_other: Affine = other_public.clone().into(); + let res_j = aff_pub_j.add_ge(&aff_pub_other); + aff_pub.set_gej(&res_j); + aff_to_public(&mut aff_pub) +} + +struct SecretScalar(pub Scalar); + +impl Drop for SecretScalar { + fn drop(&mut self) { + self.0.clear(); + } +} + +pub fn public_mul(pub_key: PublicKey, sec_key: &SecretKey) -> Result { +/* let mut sec_scal = Scalar::default(); + sec_scal.set_b32(&sec_key.serialize());*/ + + let sec_scal = SecretScalar(sec_key.clone().into()); + let mut pub_aff: Affine = pub_key.into(); + let mut pub_jac = Jacobian::default(); + pub_jac.set_ge(&pub_aff); + + //ECMULT_GEN_CONTEXT.ecmult_gen(&mut pub_jac, &sec_scal); + //pub_aff.set_gej(&pub_jac); + let mut zero = Scalar::default(); + zero.set_int(0); + let mut res = Jacobian::default(); + ECMULT_CONTEXT.ecmult(&mut res, &pub_jac, &sec_scal.0, &zero); + pub_aff.set_gej(&res); + aff_to_public(&mut pub_aff) +} + +/* private inner method but this would avoid a scalar instantiation +fn mul_in_place_scalar(a: &mut Scalar, b: &Scalar) { + let mut l = [0u32; 16]; + a.mul_512(b, &mut l); + a.reduce_512(&l); +} +*/ + +pub fn secret_mul(sec_key: SecretKey, other_sec_key: &SecretKey) -> Result { + let sec_scal = SecretScalar(sec_key.clone().into()); + let other_sec_scal = SecretScalar(other_sec_key.clone().into()); + // we could use * operator instead. + let mut res = SecretScalar(Scalar::default()); + res.0.mul_in_place(&sec_scal.0, &other_sec_scal.0); + SecretKey::parse(&res.0.b32()) +} + +pub fn secret_add(sec_key: SecretKey, other_sec_key: &SecretKey) -> Result { + let sec_scal = SecretScalar(sec_key.clone().into()); + let other_sec_scal = SecretScalar(other_sec_key.clone().into()); + // we could use + operator instead. + let mut res = SecretScalar(Scalar::default()); + res.0.add_in_place(&sec_scal.0, &other_sec_scal.0); + SecretKey::parse(&res.0.b32()) +} + +pub fn secret_inv(sec_key: SecretKey) -> Result { + let sec_scal = SecretScalar(sec_key.clone().into()); + let mut res = SecretScalar(Scalar::default()); + res.0.inv_in_place(&sec_scal.0); + SecretKey::parse(&res.0.b32()) +} + + + + + +#[cfg(test)] +mod tests { + extern crate rand; + use super::{ + sign, + secret_from_slice, + verify_public, + recover, + generate_keypair, + public_to_vec, + secret_to_vec, + public_add, + public_from_slice, + public_mul, + minus_one_key, + secret_mul, + secret_inv, + one_key, + }; + use self::rand::OsRng; + + #[test] + fn sign_val() { + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let message = vec![2;32]; + let signature = sign(&sk[..], &message).unwrap(); + assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); + } + + #[test] + fn sign_and_recover_public() { + let mut osrng = OsRng::new().expect("test"); + let (secret, public) = generate_keypair(&mut osrng); + let message = vec![2;32]; + let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); + assert_eq!(&public_to_vec(&public).as_ref()[..], &recover(&signature, &message).unwrap()[..]); + } + + #[test] + fn sign_and_verify_public() { + let mut osrng = OsRng::new().expect("test"); + let (secret, public) = generate_keypair(&mut osrng); + let message = vec![0;32]; + let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); + assert!(verify_public(&public_to_vec(&public).as_ref()[..], &signature, &message).unwrap()); + } + + #[test] + fn public_addition() { + let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; + let pub1 = public_from_slice(&pk1[..]).unwrap(); + let pub2 = public_from_slice(&pk2[..]).unwrap(); + let res = public_add(pub1, &pub2).unwrap(); + + assert_eq!(&public_to_vec(&res).as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + } + + #[test] + fn public_multiplication() { + let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let pubk = public_from_slice(&pk[..]).unwrap(); + let sec = secret_from_slice(&sk[..]).unwrap(); + let res = public_mul(pubk, &sec).unwrap(); + + assert_eq!(&public_to_vec(&res).as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + } + + + #[test] + fn public_addition_is_commutative() { + let mut osrng = OsRng::new().expect("test"); + let (_, public1) = generate_keypair(&mut osrng); + let (_, public2) = generate_keypair(&mut osrng); + + let left = public_add(public1.clone(), &public2).unwrap(); + + let right = public_add(public2.clone(), &public1).unwrap(); + + assert_eq!(left, right); + } + + #[test] + fn public_addition_is_reversible_with_subtraction() { + let mut osrng = OsRng::new().expect("test"); + let (_, public1) = generate_keypair(&mut osrng); + let (_, public2) = generate_keypair(&mut osrng); + + let sum = public_add(public1.clone(), &public2).unwrap(); + let op = public_mul(public2.clone(), minus_one_key()).unwrap(); + let sum = public_add(sum, &op).unwrap(); + + assert_eq!(sum, public1); + } + + + #[test] + fn multiplicating_secret_inversion_with_secret_gives_one() { + let mut osrng = OsRng::new().expect("test"); + let (secret, _) = generate_keypair(&mut osrng); + let inversion = secret_inv(secret.clone()).unwrap(); + let inversion = secret_mul(inversion, &secret).unwrap(); + assert_eq!(inversion, *one_key()); + } + + #[test] + fn secret_inversion_is_reversible_with_inversion() { + let mut osrng = OsRng::new().expect("test"); + let (secret, _) = generate_keypair(&mut osrng); + let inversion = secret_inv(secret.clone()).unwrap(); + let inversion = secret_inv(inversion).unwrap(); + assert_eq!(inversion, secret); + } + +} From a502a11dce2a82aa82498636f30315c4dee9dc89 Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 18 Oct 2018 12:07:15 +0200 Subject: [PATCH 08/39] Some last munute change for wasm secp, usage of a trait is definitely needed (some details of call from parity-ethereum are not understandable otherwhise). --- parity-crypto/src/secp256k1.rs | 7 +++++-- parity-crypto/src/secp256k1_alt.rs | 24 +++++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index 0f7ef94a1..78b801af9 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -117,8 +117,11 @@ pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { a_vec } +pub fn public_is_valid(p: &PublicKey) -> bool { + p.is_valid() +} + /// only for test (or make the result erasable) -#[cfg(test)] pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { p[..].to_vec() } @@ -202,7 +205,7 @@ mod tests { public_from_slice, public_mul, minus_one_key, - secret_mul, + secret_mul, secret_inv, one_key, }; diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index d46db0409..f7d0f9e4a 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -69,10 +69,10 @@ pub const GENERATOR_Y: [u8; 32] = [ /// The order of the secp256k1 curve pub const CURVE_ORDER: [u8; 32] = [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 ]; lazy_static! { @@ -151,13 +151,19 @@ pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { a_vec[1..65].to_vec() } +pub fn public_is_valid(p: &PublicKey) -> bool { + // Check from other implementation only look for a non zero value in fields + // here we can + let aff: Affine = p.clone().into(); + aff.is_valid_var() +} + /// ret size 33 pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { p.serialize_compressed().to_vec() } /// only for test (or make the result erasable) -#[cfg(test)] pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { p.serialize() } @@ -210,9 +216,9 @@ pub fn public_add(pub_key: PublicKey, other_public: &PublicKey) -> Result Result { @@ -286,7 +292,7 @@ mod tests { public_from_slice, public_mul, minus_one_key, - secret_mul, + secret_mul, secret_inv, one_key, }; From ccb7f0a2562d1d445a4ea420c3d4b341c7374c4f Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 25 Oct 2018 19:57:46 +0200 Subject: [PATCH 09/39] Added some compat wasm crate. First compat is OsRng, which would probably soon be useless (0.6 of rand?). Make it works half 0.4/0.5 , it would be a great idea to move all crates to 0.5. --- Cargo.toml | 3 +- parity-crypto/Cargo.toml | 3 +- parity-crypto/src/secp256k1_alt.rs | 14 +++- parity-wasm-compat/Cargo.toml | 24 +++++++ parity-wasm-compat/README.md | 11 ++++ parity-wasm-compat/src/lib.rs | 20 ++++++ parity-wasm-compat/src/rng/mod.rs | 32 ++++++++++ parity-wasm-compat/src/rng/rng_browser.rs | 78 +++++++++++++++++++++++ 8 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 parity-wasm-compat/Cargo.toml create mode 100644 parity-wasm-compat/README.md create mode 100644 parity-wasm-compat/src/lib.rs create mode 100644 parity-wasm-compat/src/rng/mod.rs create mode 100644 parity-wasm-compat/src/rng/rng_browser.rs diff --git a/Cargo.toml b/Cargo.toml index a8796ce87..88365ec7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,6 @@ members = [ "trace-time", "trie-standardmap", "triehash", - "uint" + "uint", + "parity-wasm-compat" ] diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index fc291381f..e5c3e8db1 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -19,17 +19,18 @@ digest = "0.8" aes = "0.2.0" aes-ctr = "0.1.0" block-modes = "0.1.0" -rand = "0.4" lazy_static = "1.0" # for secp [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.12" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } +rand = "0.4" [target.'cfg(target_arch = "wasm32")'.dependencies] hmac = "0.7" subtle = { version = "1.0", features = ["nightly"] } libsecp256k1 = { version = "0.1", package = "libsecp256k1" } +rand = "0.5" [dev-dependencies] hmac = "0.7" diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index f7d0f9e4a..e5ec8bd36 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -137,9 +137,21 @@ pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { Ok(res) } +/// random secret key for rand 0.5 +pub fn random_sec(rng: &mut R) -> SecretKey { + loop { + let mut ret = [0u8; 32]; + rng.fill_bytes(&mut ret); + + match SecretKey::parse(&ret) { + Ok(key) => return key, + Err(_) => (), + } + } +} pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { - let secret_key = SecretKey::random(r); + let secret_key = random_sec(r); let public_key = PublicKey::from_secret_key(&secret_key); (secret_key, public_key) } diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml new file mode 100644 index 000000000..3ad934337 --- /dev/null +++ b/parity-wasm-compat/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "parity-wasm-compat" +version = "0.1.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] +repository = "https://github.com/paritytech/parity-common" +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +rand = "0.4" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +web-sys = { version = "0.3", features = ["Window", "Crypto"], optional = true } +rand = "0.5" + + +[features] +default=["browser-wasm"] +browser-wasm=["web-sys"] +extrinsic-wasm=[] +node-wasm=[] diff --git a/parity-wasm-compat/README.md b/parity-wasm-compat/README.md new file mode 100644 index 000000000..b1f07db93 --- /dev/null +++ b/parity-wasm-compat/README.md @@ -0,0 +1,11 @@ +# parity-wasm-compat + +Compatibility crate for different wasm output, and to keep existing non wasm usage. + +This is a crate hosting common abstraction over multiple missing stdlib compatibility. + +Those functionality are mainly here until better alternative are published or usable. + +This crate is mainly here to avoid code redundancy and focus on opinionated parity related usage (for instance browser wasm thread could simply be a synchronous execution : that obviously only works for a small category of code and is not equivalent). + + diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs new file mode 100644 index 000000000..cbcdf6d19 --- /dev/null +++ b/parity-wasm-compat/src/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Parity wasm compat crate. + +pub mod rng; + diff --git a/parity-wasm-compat/src/rng/mod.rs b/parity-wasm-compat/src/rng/mod.rs new file mode 100644 index 000000000..34458b0f6 --- /dev/null +++ b/parity-wasm-compat/src/rng/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! rng alternative implementation, note that future version of rand crate will probably cover that +//! (at the time it uses stdweb and emscripten only). +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod rng_browser; + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use self::rng_browser::OsRng; + +#[cfg(not(target_arch = "wasm32"))] +mod rng_std { + pub use rand::OsRng; +} + +#[cfg(not(target_arch = "wasm32"))] +pub use self::rng_std::OsRng; diff --git a/parity-wasm-compat/src/rng/rng_browser.rs b/parity-wasm-compat/src/rng/rng_browser.rs new file mode 100644 index 000000000..0e1d8cead --- /dev/null +++ b/parity-wasm-compat/src/rng/rng_browser.rs @@ -0,0 +1,78 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! rng adapter for wasm in browser (using websys crate) + +use web_sys::{Crypto}; +use rand::{CryptoRng, RngCore, Error, ErrorKind}; +use std::fmt; +use std::mem::transmute; + +#[derive(Clone)] +pub struct OsRng; + +impl fmt::Debug for OsRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "OsRng using webcrypto rng source".fmt(f) + } +} + +impl OsRng { + pub fn new() -> Result { + Ok(OsRng) + } +} + +impl CryptoRng for OsRng {} + +// current buffer usage is quite ineficient +impl RngCore for OsRng { + + fn next_u32(&mut self) -> u32 { + let result: u32 = 0; + let mut buf: [u8; 4] = unsafe { transmute(result) }; + let crypto: Crypto = web_sys::window().unwrap().crypto().unwrap(); + crypto.get_random_values_with_u8_array(&mut buf[..]).expect("Not able to operate without random source."); + unsafe { transmute(buf) } + } + + fn next_u64(&mut self) -> u64 { + let result: u64 = 0; + let mut buf: [u8; 8] = unsafe { transmute(result) }; + let crypto: Crypto = web_sys::window().unwrap().crypto().unwrap(); + crypto.get_random_values_with_u8_array(&mut buf[..]).expect("Not able to operate without random source."); + unsafe { transmute(buf) } + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + let crypto: Crypto = web_sys::window().unwrap().crypto().unwrap(); + crypto.get_random_values_with_u8_array(dest).expect("Not able to operate without random source."); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + if let Some(window) = web_sys::window() { + let crypto = window.crypto() + .map_err(|_jsval|Error::new(ErrorKind::Unexpected, "Error accessing webcrypto in browser"))?; + crypto.get_random_values_with_u8_array(dest) + .map_err(|_jsval|Error::new(ErrorKind::Unexpected, "Error getting random value from webcrypto"))?; + Ok(()) + } else { + Err(Error::new(ErrorKind::Unavailable, "error getting window")) + } + } + +} + From f606daade14eeca0e7f266776c7c55d1a3dc94ff Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 26 Oct 2018 18:02:26 +0200 Subject: [PATCH 10/39] Single threadpool compat. --- parity-wasm-compat/Cargo.toml | 1 + parity-wasm-compat/src/lib.rs | 2 + parity-wasm-compat/src/rng/rng_browser.rs | 4 +- parity-wasm-compat/src/threadpool/mod.rs | 32 +++++++ .../threadpool/threadpool_browser_single.rs | 92 +++++++++++++++++++ 5 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 parity-wasm-compat/src/threadpool/mod.rs create mode 100644 parity-wasm-compat/src/threadpool/threadpool_browser_single.rs diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml index 3ad934337..b13d4c057 100644 --- a/parity-wasm-compat/Cargo.toml +++ b/parity-wasm-compat/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["cdylib", "rlib"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rand = "0.4" +threadpool = "1.7" [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3", features = ["Window", "Crypto"], optional = true } diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs index cbcdf6d19..d36a80f62 100644 --- a/parity-wasm-compat/src/lib.rs +++ b/parity-wasm-compat/src/lib.rs @@ -15,6 +15,8 @@ // along with Parity. If not, see . //! Parity wasm compat crate. +#![feature(fn_traits)] pub mod rng; +pub mod threadpool; diff --git a/parity-wasm-compat/src/rng/rng_browser.rs b/parity-wasm-compat/src/rng/rng_browser.rs index 0e1d8cead..f032ab335 100644 --- a/parity-wasm-compat/src/rng/rng_browser.rs +++ b/parity-wasm-compat/src/rng/rng_browser.rs @@ -16,8 +16,8 @@ //! rng adapter for wasm in browser (using websys crate) -use web_sys::{Crypto}; -use rand::{CryptoRng, RngCore, Error, ErrorKind}; +use web_sys::Crypto; +use rand::{ CryptoRng, RngCore, Error, ErrorKind }; use std::fmt; use std::mem::transmute; diff --git a/parity-wasm-compat/src/threadpool/mod.rs b/parity-wasm-compat/src/threadpool/mod.rs new file mode 100644 index 000000000..5c517bd9f --- /dev/null +++ b/parity-wasm-compat/src/threadpool/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! threadpool compatibility + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod threadpool_browser_single; + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use self::threadpool_browser_single::{ Builder, ThreadPool }; + +#[cfg(not(target_arch = "wasm32"))] +mod threadpool_crate { + pub use threadpool::{ Builder, ThreadPool }; // need build then from pool max_count and execute +} + +#[cfg(not(target_arch = "wasm32"))] +pub use self::threadpool_crate::*; diff --git a/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs b/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs new file mode 100644 index 000000000..5f3677920 --- /dev/null +++ b/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs @@ -0,0 +1,92 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Threadpool forcing single thread synchronous usage. +//! Very likely to break existing code (implicit switch between asynchronous and synchronous +//! paradigm), because we do not ensure it runs only for unique thread configuration. +//! +//! A variant of this execution should allow running suspendable execution to run more use case. +//! + +#[derive(Clone, Default)] +pub struct Builder(Option); + +pub struct ThreadPool(Option); + + +impl Builder { + pub fn new() -> Builder { + Builder(None) + } + + pub fn num_threads(self, _num_threads: usize) -> Builder { + // do nothing (no error either (flexibility for usage in existing code)). + self + } + + + pub fn thread_name(mut self, name: String) -> Builder { + self.0 = Some(name); + self + } + + pub fn thread_stack_size(self, _size: usize) -> Builder { + // unmanaged + self + } + + pub fn build(self) -> ThreadPool { + ThreadPool(self.0) + } + +} + +impl ThreadPool { + + pub fn new(num_threads: usize) -> ThreadPool { + Builder::new().num_threads(num_threads).build() + } + + pub fn with_name(name: String, num_threads: usize) -> ThreadPool { + Builder::new().thread_name(name).num_threads(num_threads).build() + } + + pub fn queued_count(&self) -> usize { + // cannot queue with synch ex + 0 + } + + pub fn active_count(&self) -> usize { + // cannot query running with non suspendable synch ex + 0 + } + + pub fn max_count(&self) -> usize { std::usize::MAX } + + pub fn panic_count(&self) -> usize { 0 } + + pub fn set_num_threads(&mut self, _num_threads: usize) { } + + pub fn join(&self) { } + + pub fn execute(&self, job: F) + where + F: FnOnce() + Send + 'static, + { + job.call_once(()) + } + +} From 5b2aef675025d5495eadc9fa175dc35fc5926f97 Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 29 Oct 2018 12:11:54 +0100 Subject: [PATCH 11/39] Add single direction single thread mpsc (can be use under certain condition with single thread threadpool (see ethkey command)). --- parity-wasm-compat/src/lib.rs | 1 + parity-wasm-compat/src/mpsc/mod.rs | 32 +++++++++ .../src/mpsc/mpsc_browser_single.rs | 65 +++++++++++++++++++ .../threadpool/threadpool_browser_single.rs | 5 +- 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 parity-wasm-compat/src/mpsc/mod.rs create mode 100644 parity-wasm-compat/src/mpsc/mpsc_browser_single.rs diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs index d36a80f62..6885fbd8e 100644 --- a/parity-wasm-compat/src/lib.rs +++ b/parity-wasm-compat/src/lib.rs @@ -19,4 +19,5 @@ pub mod rng; pub mod threadpool; +pub mod mpsc; diff --git a/parity-wasm-compat/src/mpsc/mod.rs b/parity-wasm-compat/src/mpsc/mod.rs new file mode 100644 index 000000000..0859686ae --- /dev/null +++ b/parity-wasm-compat/src/mpsc/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! mpsc compatibility + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod mpsc_browser_single; + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use self::mpsc_browser_single::*; + +#[cfg(not(target_arch = "wasm32"))] +mod mpsc_crate { + pub use std::sync::mpsc::{ sync_channel, SyncSender, Receiver }; // need build then from pool max_count and execute +} + +#[cfg(not(target_arch = "wasm32"))] +pub use self::mpsc_crate::*; diff --git a/parity-wasm-compat/src/mpsc/mpsc_browser_single.rs b/parity-wasm-compat/src/mpsc/mpsc_browser_single.rs new file mode 100644 index 000000000..905f2935a --- /dev/null +++ b/parity-wasm-compat/src/mpsc/mpsc_browser_single.rs @@ -0,0 +1,65 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! mpsc single thread compatibility (very minimal, could only run on particular conditions for +//! instance adding result from threads) + +use std::rc::Rc; +use std::cell::RefCell; +use std::sync::mpsc::{ SendError, RecvError }; +use std::collections::VecDeque; + +pub struct SyncSender(Rc>>); + +unsafe impl Send for SyncSender {} + +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + SyncSender(self.0.clone()) + } +} + + +pub struct Receiver(Rc>>); + +pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { + let v = Rc::new(RefCell::new(VecDeque::with_capacity(bound))); + (SyncSender(v.clone()), Receiver(v)) +} + +impl SyncSender { + + pub fn send(&self, t: T) -> Result<(), SendError> { + self.0.borrow_mut().push_front(t); + Ok(()) + } + +} + + +impl Receiver { + + pub fn recv(&self) -> Result { + if let Some(t) = self.0.borrow_mut().pop_front() { + Ok(t) + } else { + Err(RecvError) + } + } + +} + diff --git a/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs b/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs index 5f3677920..d535ea9f3 100644 --- a/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs +++ b/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs @@ -74,7 +74,10 @@ impl ThreadPool { 0 } - pub fn max_count(&self) -> usize { std::usize::MAX } + pub fn max_count(&self) -> usize { + // single thread + 1 + } pub fn panic_count(&self) -> usize { 0 } From c57fb091f8c518b2b663403028222461caaafa8b Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 29 Oct 2018 15:59:53 +0100 Subject: [PATCH 12/39] ring to 0.13 --- parity-crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index e5c3e8db1..c93f0ad9a 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -22,7 +22,7 @@ block-modes = "0.1.0" lazy_static = "1.0" # for secp [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -ring = "0.12" +ring = "0.13" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } rand = "0.4" From 85d2f804018d5bf896483375284a45b8bb857498 Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 29 Oct 2018 17:32:26 +0100 Subject: [PATCH 13/39] home_dir to '/home' for browser. --- parity-wasm-compat/Cargo.toml | 1 + parity-wasm-compat/src/lib.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml index b13d4c057..1a53519d8 100644 --- a/parity-wasm-compat/Cargo.toml +++ b/parity-wasm-compat/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["cdylib", "rlib"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies] rand = "0.4" threadpool = "1.7" +home = "0.3" [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3", features = ["Window", "Crypto"], optional = true } diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs index 6885fbd8e..9766864d2 100644 --- a/parity-wasm-compat/src/lib.rs +++ b/parity-wasm-compat/src/lib.rs @@ -21,3 +21,17 @@ pub mod rng; pub mod threadpool; pub mod mpsc; +pub mod home { + #[cfg(not(target_arch = "wasm32"))] + extern crate home; + #[cfg(not(target_arch = "wasm32"))] + pub use home::home_dir; + + #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] + use std::path::PathBuf; + #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] + pub fn home_dir() -> Option { + // need a dummy dir for whatever browser mapping we use + Some(PathBuf::from("/home")) + } +} From 58c9e725b1c93eb6568600eda7057d3eb23580c7 Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 29 Oct 2018 18:07:09 +0100 Subject: [PATCH 14/39] dummy memmap --- parity-wasm-compat/Cargo.toml | 1 + parity-wasm-compat/src/lib.rs | 1 + parity-wasm-compat/src/memmap.rs | 76 ++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 parity-wasm-compat/src/memmap.rs diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml index 1a53519d8..651f3aa50 100644 --- a/parity-wasm-compat/Cargo.toml +++ b/parity-wasm-compat/Cargo.toml @@ -13,6 +13,7 @@ crate-type = ["cdylib", "rlib"] rand = "0.4" threadpool = "1.7" home = "0.3" +memmap = "0.7" [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3", features = ["Window", "Crypto"], optional = true } diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs index 9766864d2..879075f44 100644 --- a/parity-wasm-compat/src/lib.rs +++ b/parity-wasm-compat/src/lib.rs @@ -20,6 +20,7 @@ pub mod rng; pub mod threadpool; pub mod mpsc; +pub mod memmap; pub mod home { #[cfg(not(target_arch = "wasm32"))] diff --git a/parity-wasm-compat/src/memmap.rs b/parity-wasm-compat/src/memmap.rs new file mode 100644 index 000000000..b68c3ec12 --- /dev/null +++ b/parity-wasm-compat/src/memmap.rs @@ -0,0 +1,76 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! memmap non breaking compile implementation, note that it is non functional + +#[cfg(not(target_arch = "wasm32"))] +extern crate memmap; + +#[cfg(not(target_arch = "wasm32"))] +pub use memmap::MmapMut; + +#[cfg(target_arch = "wasm32")] +pub struct MmapMut; + +#[cfg(target_arch = "wasm32")] +use std::io::{ErrorKind, Result}; + +#[cfg(target_arch = "wasm32")] +use std::fs::File; + +#[cfg(target_arch = "wasm32")] +use std::ops::{Deref, DerefMut}; + +#[cfg(target_arch = "wasm32")] +impl MmapMut { + + pub unsafe fn map_mut(_file: &File) -> Result { + Err(ErrorKind::Other.into()) + } + + pub fn flush(&self) -> Result<()> { + Err(ErrorKind::Other.into()) + } +} + + +#[cfg(target_arch = "wasm32")] +impl Deref for MmapMut { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + unimplemented!() + } +} + +#[cfg(target_arch = "wasm32")] +impl DerefMut for MmapMut { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + unimplemented!() + } +} + +#[cfg(target_arch = "wasm32")] +impl AsRef<[u8]> for MmapMut { + #[inline] + fn as_ref(&self) -> &[u8] { + unimplemented!() + } +} + From 41481dd3eff6e1d977b9b24eb010e4b2acf1d6c8 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 30 Oct 2018 10:33:58 +0100 Subject: [PATCH 15/39] Allow heapsize on wasm32. --- fixed-hash/src/hash.rs | 4 ++-- parity-wasm-compat/Cargo.toml | 3 ++- parity-wasm-compat/src/lib.rs | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fixed-hash/src/hash.rs b/fixed-hash/src/hash.rs index e9bb7e1a2..fca4fb7aa 100644 --- a/fixed-hash/src/hash.rs +++ b/fixed-hash/src/hash.rs @@ -457,7 +457,7 @@ macro_rules! impl_hash_uint_conversions { } } -#[cfg(all(feature="heapsizeof", feature="libc", not(target_os = "unknown")))] +#[cfg(all(feature="heapsizeof", any(not(target_os = "unknown"), target_arch = "wasm32")))] #[macro_export] #[doc(hidden)] macro_rules! impl_heapsize_for_hash { @@ -470,7 +470,7 @@ macro_rules! impl_heapsize_for_hash { } } -#[cfg(any(not(feature="heapsizeof"), not(feature="libc"), target_os = "unknown"))] +#[cfg(any(not(feature="heapsizeof"), all(target_os = "unknown", not(target_arch = "wasm32"))))] #[macro_export] #[doc(hidden)] macro_rules! impl_heapsize_for_hash { diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml index 651f3aa50..230ed292e 100644 --- a/parity-wasm-compat/Cargo.toml +++ b/parity-wasm-compat/Cargo.toml @@ -14,11 +14,12 @@ rand = "0.4" threadpool = "1.7" home = "0.3" memmap = "0.7" +parity-snappy = { version = "0.1" } [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3", features = ["Window", "Crypto"], optional = true } rand = "0.5" - +snap = "0.2" [features] default=["browser-wasm"] diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs index 879075f44..7c3ab6441 100644 --- a/parity-wasm-compat/src/lib.rs +++ b/parity-wasm-compat/src/lib.rs @@ -21,6 +21,7 @@ pub mod rng; pub mod threadpool; pub mod mpsc; pub mod memmap; +pub mod snappy; pub mod home { #[cfg(not(target_arch = "wasm32"))] From 4b72742594126bd1f98410e9a144fff9d4c427d8 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 30 Oct 2018 11:32:43 +0100 Subject: [PATCH 16/39] Pbkdf2 RustCrypto alternative. --- parity-crypto/Cargo.toml | 2 ++ parity-crypto/src/lib.rs | 8 ++++--- parity-crypto/src/pbkdf2.rs | 10 ++++++++ parity-crypto/src/pbkdf2_alt.rs | 42 +++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 parity-crypto/src/pbkdf2_alt.rs diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index c93f0ad9a..8c28aa3c6 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -31,8 +31,10 @@ hmac = "0.7" subtle = { version = "1.0", features = ["nightly"] } libsecp256k1 = { version = "0.1", package = "libsecp256k1" } rand = "0.5" +pbkdf2 = { version = "0.3", default-features = false } [dev-dependencies] hmac = "0.7" libsecp256k1 = { version = "0.1", package = "libsecp256k1" } +pbkdf2 = { version = "0.3", default-features = false } diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 1704a8258..569419a4a 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -59,10 +59,13 @@ pub mod secp256k1_alt; #[cfg(target_arch = "wasm32")] pub mod secp256k1; -// could create a less safe crate using RustCrypto or just switch +#[cfg(all(not(target_arch = "wasm32"), test))] +pub mod pbkdf2_alt; #[cfg(not(target_arch = "wasm32"))] pub mod pbkdf2; -// could create a less safe crate using RustCrypto or just switch +#[path = "pbkdf2_alt.rs"] +#[cfg(target_arch = "wasm32")] +pub mod pbkdf2; pub use error::Error; @@ -89,7 +92,6 @@ impl Keccak256<[u8; 32]> for T where T: AsRef<[u8]> { } } -#[cfg(not(target_arch = "wasm32"))] pub fn derive_key_iterations(password: &[u8], salt: &[u8], c: u32) -> (Vec, Vec) { let mut derived_key = [0u8; KEY_LENGTH]; pbkdf2::sha256(c, pbkdf2::Salt(salt), pbkdf2::Secret(password), &mut derived_key); diff --git a/parity-crypto/src/pbkdf2.rs b/parity-crypto/src/pbkdf2.rs index d210f6f65..9cc830716 100644 --- a/parity-crypto/src/pbkdf2.rs +++ b/parity-crypto/src/pbkdf2.rs @@ -26,3 +26,13 @@ pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) } + +#[test] +fn basic_test() { + let mut dest = [0;32]; + let salt = [5;32]; + let secret = [7;32]; + sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); + let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; + assert_eq!(res, dest); +} diff --git a/parity-crypto/src/pbkdf2_alt.rs b/parity-crypto/src/pbkdf2_alt.rs new file mode 100644 index 000000000..f9a483b57 --- /dev/null +++ b/parity-crypto/src/pbkdf2_alt.rs @@ -0,0 +1,42 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate pbkdf2; +extern crate hmac; +use self::hmac::Hmac; + +use rsha2::{Sha256, Sha512}; + +pub struct Salt<'a>(pub &'a [u8]); +pub struct Secret<'a>(pub &'a [u8]); + +pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { + self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) +} + +pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { + self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) +} + +#[test] +fn basic_test() { + let mut dest = [0;32]; + let salt = [5;32]; + let secret = [7;32]; + sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); + let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; + assert_eq!(res, dest); +} From 1c5b4b1036f99e9c7aa91c571483802dae51dccb Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 30 Oct 2018 11:34:10 +0100 Subject: [PATCH 17/39] tabs --- parity-crypto/src/pbkdf2_alt.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/parity-crypto/src/pbkdf2_alt.rs b/parity-crypto/src/pbkdf2_alt.rs index f9a483b57..2a8900ca6 100644 --- a/parity-crypto/src/pbkdf2_alt.rs +++ b/parity-crypto/src/pbkdf2_alt.rs @@ -24,19 +24,19 @@ pub struct Salt<'a>(pub &'a [u8]); pub struct Secret<'a>(pub &'a [u8]); pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { - self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) + self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) } pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { - self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) + self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) } #[test] fn basic_test() { - let mut dest = [0;32]; - let salt = [5;32]; - let secret = [7;32]; - sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); - let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; - assert_eq!(res, dest); + let mut dest = [0;32]; + let salt = [5;32]; + let secret = [7;32]; + sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); + let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; + assert_eq!(res, dest); } From 3ff4e305ca33eb76fe33f2c8684dce54e9b762e1 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 30 Oct 2018 11:38:01 +0100 Subject: [PATCH 18/39] Missing file for snappy compat. --- parity-wasm-compat/src/snappy.rs | 92 ++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 parity-wasm-compat/src/snappy.rs diff --git a/parity-wasm-compat/src/snappy.rs b/parity-wasm-compat/src/snappy.rs new file mode 100644 index 000000000..d410288b6 --- /dev/null +++ b/parity-wasm-compat/src/snappy.rs @@ -0,0 +1,92 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Use rust native snappy for wasm32 + + +#[cfg(target_arch = "wasm32")] +extern crate snap; + +#[cfg(not(target_arch = "wasm32"))] +extern crate parity_snappy; + +#[cfg(not(target_arch = "wasm32"))] +pub use parity_snappy as snappy; + + +#[cfg(target_arch = "wasm32")] +pub mod snappy { + + use std::fmt; + + #[inline] + pub fn max_compressed_len(len: usize) -> usize { + snap::max_compress_len(len) + } + pub fn decompressed_len(compressed: &[u8]) -> Result { + Ok(snap::decompress_len(compressed)?) + } + pub fn compress(input: &[u8]) -> Vec { + let mut enc = snap::Encoder::new(); + enc.compress_vec(input).expect("No failure on compression") + } + // TODO this proto is not really efficient, snappy compression should use inline buffered + // see snap writer and reader trait (plus return error) + pub fn compress_into(input: &[u8], output: &mut Vec) -> usize { + let mut enc = snap::Encoder::new(); + let l = max_compressed_len(input.len()); + if output.len() < l { + output.resize(l,0); + } + enc.compress(input, &mut output[..]).expect("No failure on compression") + } + pub fn decompress(input: &[u8]) -> Result, InvalidInput> { + let mut dec = snap::Decoder::new(); + Ok(dec.decompress_vec(input)?) + } + // TODO this proto is not really efficient, snappy compression should use inline buffered + // This is bad it build huge buffer + pub fn decompress_into(input: &[u8], output: &mut Vec) -> Result { + let mut dec = snap::Decoder::new(); + let l = decompressed_len(input)?; + if output.len() < l { + output.resize(l,0); + } + Ok(dec.decompress(input, &mut output[..])?) + } + + #[derive(Debug)] + pub struct InvalidInput; + + impl std::error::Error for InvalidInput { + fn description(&self) -> &str { + "Attempted snappy decompression with invalid input" + } + } + + impl fmt::Display for InvalidInput { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Attempted snappy decompression with invalid input") + } + } + + impl std::convert::From for InvalidInput { + fn from(_: snap::Error) -> Self { + InvalidInput + } + } + +} From 37a38dc7352e3910447deeb1d8e6e72a3b9d028a Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 1 Nov 2018 20:10:53 +0100 Subject: [PATCH 19/39] =?UTF-8?q?Some=20wasmp=20compat.=20-=20hook=20print?= =?UTF-8?q?=20to=20redirect=20globally=20to=20console.=20-=20memap=20to=20?= =?UTF-8?q?fix=20compilation=20errors=20:=20do=20not=20use=20-=20time=20-?= =?UTF-8?q?=20fs=20:=C2=A0very=20incomplete=20(would=20need=20path=20suppo?= =?UTF-8?q?rt,=20still=20metadata=20could=20be=20quick=20and=20simple=20to?= =?UTF-8?q?=20add).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parity-wasm-compat/Cargo.toml | 9 +- parity-wasm-compat/src/fs/fs_browser.rs | 373 ++++++++++++++++++++++++ parity-wasm-compat/src/fs/mod.rs | 34 +++ parity-wasm-compat/src/hook_print.rs | 90 ++++++ parity-wasm-compat/src/lib.rs | 28 ++ parity-wasm-compat/src/memmap.rs | 3 - parity-wasm-compat/src/tempdir.rs | 48 +++ parity-wasm-compat/src/time.rs | 142 +++++++++ 8 files changed, 722 insertions(+), 5 deletions(-) create mode 100644 parity-wasm-compat/src/fs/fs_browser.rs create mode 100644 parity-wasm-compat/src/fs/mod.rs create mode 100644 parity-wasm-compat/src/hook_print.rs create mode 100644 parity-wasm-compat/src/tempdir.rs create mode 100644 parity-wasm-compat/src/time.rs diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml index 230ed292e..e2fbeaf38 100644 --- a/parity-wasm-compat/Cargo.toml +++ b/parity-wasm-compat/Cargo.toml @@ -15,14 +15,19 @@ threadpool = "1.7" home = "0.3" memmap = "0.7" parity-snappy = { version = "0.1" } +tempdir = {version="0.3", optional = true} [target.'cfg(target_arch = "wasm32")'.dependencies] -web-sys = { version = "0.3", features = ["Window", "Crypto"], optional = true } +wasm-bindgen = { version = "0.2", optional = true } +web-sys = { version = "0.3", features = ["Window", "Crypto", "Performance", "console"], optional = true } +js-sys = { version = "0.3", optional = true} + rand = "0.5" snap = "0.2" [features] default=["browser-wasm"] -browser-wasm=["web-sys"] +browser-wasm=["web-sys","js-sys","wasm-bindgen"] extrinsic-wasm=[] node-wasm=[] +use-tempdir=["tempdir"] diff --git a/parity-wasm-compat/src/fs/fs_browser.rs b/parity-wasm-compat/src/fs/fs_browser.rs new file mode 100644 index 000000000..25b19bd95 --- /dev/null +++ b/parity-wasm-compat/src/fs/fs_browser.rs @@ -0,0 +1,373 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! fs compatibility (very limited) + + +use std::io::{ self, Read, Write, Seek, SeekFrom }; +use std::path::Path; +use wasm_bindgen::prelude::*; + +// put in module env for now +#[wasm_bindgen(module = "env")] +extern "C" { + + pub type JsFile; + + #[wasm_bindgen(catch)] + fn open_browserfs(path: &str, option: i32) -> Result; + + #[wasm_bindgen(catch)] + fn read_browserfs(jsfile: &JsFile, buff: *mut u8, len: u32) -> Result; + + #[wasm_bindgen(catch)] + fn write_browserfs(jsfile: &JsFile, buff: *const u8, len: u32) -> Result; + + #[wasm_bindgen(catch)] + fn flush_write_browserfs(jsfile: &JsFile) -> Result<(), JsValue>; + + #[wasm_bindgen(catch)] + fn set_len_browserfs(jsfile: &JsFile, len: u64) -> Result<(), JsValue>; + + fn close_browserfs(jsfile: &JsFile); + + #[wasm_bindgen(catch)] + fn seek_browserfs(jsfile: &JsFile, mov: i64) -> Result; + + fn seek_browserfs_from_start(jsfile: &JsFile, mov: u32) -> u32; + + #[wasm_bindgen(catch)] + fn seek_browserfs_from_end(jsfile: &JsFile, mov: i64) -> Result; + + fn len_browserfs(jsfile: &JsFile) -> u64; + +} + +pub struct File(pub JsFile); + +#[allow(non_camel_case_types)] +type c_int = i32; + +#[allow(non_camel_case_types)] +type mode_t = u32; + +mod libc { + use super::c_int; + // reexport unix libc constant for file + // + pub const O_RDONLY: c_int = 0; + pub const O_WRONLY: c_int = 1; + pub const O_RDWR: c_int = 2; + + pub const O_APPEND: c_int = 1024; + + pub const O_CREAT: c_int = 64; + pub const O_EXCL: c_int = 128; + pub const O_TRUNC: c_int = 512; + + pub const EINVAL : c_int = 22; +} +/// straight copy of unix code plus create and new +#[derive(Clone, Debug)] +pub struct OpenOptions { + // generic + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, + // system-specific + custom_flags: i32, + mode: mode_t, +} + + +impl OpenOptions { + /// only non copied function from unix code + pub fn open>(&self, path: P) -> io::Result { + let tag = self.get_access_mode()? | + self.get_creation_mode()? | + (self.custom_flags as c_int); + open_browserfs(path.as_ref().to_str().expect("input from browser in utf8"), tag) + .map_err(|jsval|io::Error::new(io::ErrorKind::Other, format!("could not open file in browser: {:?}",jsval))) + .map(|jsfile|File(jsfile)) + + } + + + /// see unix openoption + pub fn new() -> OpenOptions { + OpenOptions { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + // system-specific + custom_flags: 0, + mode: 0o666, + } + } + + /// see unix openoption + pub fn read(mut self, read: bool) -> Self { self.read = read; self } + /// see unix openoption + pub fn write(mut self, write: bool) -> Self { self.write = write; self } + /// see unix openoption + pub fn append(mut self, append: bool) -> Self { self.append = append; self } + /// see unix openoption + pub fn truncate(mut self, truncate: bool) -> Self { self.truncate = truncate; self } + /// see unix openoption + pub fn create(mut self, create: bool) -> Self { self.create = create; self } + /// see unix openoption + pub fn create_new(mut self, create_new: bool) -> Self { self.create_new = create_new; self } + + /// see unix openoption + pub fn custom_flags(mut self, flags: i32) -> Self { self.custom_flags = flags; self } + /// warning curently not used TODO usable in node fs + pub fn mode(mut self, mode: u32) -> Self { self.mode = mode as mode_t; self } + + /// see unix openoption + fn get_access_mode(&self) -> io::Result { + match (self.read, self.write, self.append) { + (true, false, false) => Ok(libc::O_RDONLY), + (false, true, false) => Ok(libc::O_WRONLY), + (true, true, false) => Ok(libc::O_RDWR), + (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), + (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), + (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } + + /// see unix openoption + fn get_creation_mode(&self) -> io::Result { + match (self.write, self.append) { + (true, false) => {} + (false, false) => + if self.truncate || self.create || self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + }, + (_, true) => + if self.truncate && !self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + }, + } + + Ok(match (self.create, self.truncate, self.create_new) { + (false, false, false) => 0, + (true, false, false) => libc::O_CREAT, + (false, true, false) => libc::O_TRUNC, + (true, true, false) => libc::O_CREAT | libc::O_TRUNC, + (_, _, true) => libc::O_CREAT | libc::O_EXCL, + }) + } +} + +/* +#[derive(Clone, Debug)] +pub struct OpenOptions { + // generic + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, +} +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + } + } + + pub fn read(&mut self, read: bool) { self.read = read; } + pub fn write(&mut self, write: bool) { self.write = write; } + pub fn append(&mut self, append: bool) { self.append = append; } + pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } + pub fn create(&mut self, create: bool) { self.create = create; } + pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } + + // mapping from https://nodejs.org/api/fs.html#fs_file_system_flags + fn get_node_fs_tag(&self) -> io::Result<&str> { + const tag_r : &str = "r"; // reading, should exist + const tag_rp : &str = "r+"; // reading, should exist, + write + const tag_w : &str = "w"; // writing, truncate if exist and create if don't + const tag_wx : &str = "wx"; // writing, truncate if exist and create if don't, fail if exist + const tag_wp : &str = "w+"; // writing, truncate if exist and create if don't + const tag_wxp : &str = "wx+"; // writing, truncate if exist and create if don't, fail if exist + const tag_a : &str = "a"; // append , create if does not exist + const tag_ax : &str = "ax"; // append , create if does not exist, fail if exist + const tag_ap : &str = "a+"; // append , create if does not exist + const tag_axp : &str = "ax+"; // append , create if does not exist, fail if exist + match (self.read, self.write, self.append, self.truncate, self.create, self.create_new) { + (true, false, false, false, false, false) => Ok(&tag_r), + (true, true, false, false, false, false) => Ok(&tag_rp), + (false, true, false, true, true, false) => Ok(&tag_w), + (false, true, false, true, true, true) => Ok(&tag_wx), + (true, true, false, true, true, false) => Ok(&tag_wp), + (true, true, false, true, true, true) => Ok(&tag_wxp), + (false, _, true, false, true, false) => Ok(&tag_a), + (false, _, true, false, true, true) => Ok(&tag_ax), + (true, _, true, false, true, false) => Ok(&tag_ap), + (true, _, true, false, true, true) => Ok(&tag_axp), + _ => Err(io::Error::new(io::ErrorKind::Other, "unimplemented or non allowed openoption configuration")), + } + } +} +*/ +impl File { + + /// see std::fs::File + pub fn open>(path: P) -> io::Result { + open_browserfs(path.as_ref().to_str().expect("input from browser in utf8"), 0) + .map_err(|jsval|io::Error::new(io::ErrorKind::Other, format!("could not open file in browser: {:?}",jsval))) + .map(|jsfile|File(jsfile)) + } + + fn inner_read(&self, buf: &mut [u8]) -> io::Result { + let l = buf.len(); + match read_browserfs(&self.0, buf.as_mut_ptr(), l as u32) { + Ok(n) => Ok(n as usize), + Err(jsval) => Err(io::Error::new( + io::ErrorKind::Other, format!("could not read from file in browser: {:?}",jsval) + )), + } + } + + fn inner_write(&self, buf: &[u8]) -> io::Result { + let l = buf.len(); + match write_browserfs(&self.0, buf.as_ptr(), l as u32) { + Ok(n) => Ok(n as usize), + Err(jsval) => Err(io::Error::new( + io::ErrorKind::Other, format!("could not write in file in browser: {:?}",jsval) + )), + } + } + + fn inner_flush(&self) -> io::Result<()> { + match flush_write_browserfs(&self.0) { + Ok(n) => Ok(n), + Err(jsval) => Err(io::Error::new( + io::ErrorKind::Other, format!("error when flushing file in browser: {:?}",jsval) + )), + } + } + + // Note that if we stored jsfile in rust memory (doable (just get the fd with open), probably better design), + // we would not need to call js (except to get length for end) here + // TODO redesign if this wasm compat get used (and choice of memfs is ok), at least it + // demonstrate wasmbindgen capability (but it is a waste here). Will get a slight issue with + // mutability + fn inner_seek(&self, pos: SeekFrom) -> io::Result { + match match pos { + SeekFrom::Current(nb) => seek_browserfs(&self.0, nb), + SeekFrom::Start(nb) => Ok(seek_browserfs_from_start(&self.0, nb as u32) as u32), + SeekFrom::End(nb) => seek_browserfs_from_end(&self.0, nb), + } { + Ok(n) => Ok(n as u64), + Err(jsval) => Err(io::Error::new( + io::ErrorKind::Other, format!("seek to under zero position: {:?}",jsval) + )), + } + } + + pub fn set_len(&self, size: u64) -> io::Result<()> { + match set_len_browserfs(&self.0, size) { + Ok(n) => Ok(n), + Err(jsval) => Err(io::Error::new( + io::ErrorKind::Other, format!("error changing file length in browser: {:?}",jsval) + )), + } + } + + /// warning non conform use : would need to query stat as metada, TODO keep it with not many use + /// case + pub fn metadata(&self) -> io::Result<&Self> { + Ok(self) + } + + /// from metadata use case, move it to metadata if using stat value as metadata + /// TODO this is bad semantic indeed (can return an error) + pub fn len(&self) -> u64 { + len_browserfs(&self.0) + } + +} +impl Read for File { + + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner_read(buf) + } + +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner_write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner_flush() + } +} + +impl Seek for File { + + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.inner_seek(pos) + } +} + +impl Drop for File { + fn drop(&mut self) { + close_browserfs(&self.0); + } +} + +impl<'a> Read for &'a File { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner_read(buf) + } +} + +impl<'a> Write for &'a File { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner_write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner_flush() + } +} + +impl<'a> Seek for &'a File { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.inner_seek(pos) + } +} + + diff --git a/parity-wasm-compat/src/fs/mod.rs b/parity-wasm-compat/src/fs/mod.rs new file mode 100644 index 000000000..20dafc4ec --- /dev/null +++ b/parity-wasm-compat/src/fs/mod.rs @@ -0,0 +1,34 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! File compatibility, at this point it is only to allow very specific case (no directory +//! management, `is_file` defaulting to true is good for it). And probably only our last usecase +//! (open file and read_to_end). + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod fs_browser; + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use self::fs_browser::*; + +#[cfg(not(target_arch = "wasm32"))] +mod fs_crate { + pub use std::fs::{ File, OpenOptions }; +} + +#[cfg(not(target_arch = "wasm32"))] +pub use self::fs_crate::*; diff --git a/parity-wasm-compat/src/hook_print.rs b/parity-wasm-compat/src/hook_print.rs new file mode 100644 index 000000000..7d41c2132 --- /dev/null +++ b/parity-wasm-compat/src/hook_print.rs @@ -0,0 +1,90 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! Hook to display stdout and stderr as websys console calls + +use std::io::{ Write, Result, set_panic, set_print }; +use web_sys::console; +use wasm_bindgen::JsValue; +use js_sys::Array; + +fn write_out(v: &str) { + if v.len() > 0 { + console::log(&Array::of1(&JsValue::from(v))) + } +} +fn write_err(v: &str) { + if v.len() > 0 { + console::warn(&Array::of1(&JsValue::from(v))) + } +} + +struct Writer(pub fn(&str), pub String); + +struct NoBuffWriter(fn(&str)); + +impl Write for NoBuffWriter { + + fn write(&mut self, buf: &[u8]) -> Result { + let str_w = unsafe { std::str::from_utf8_unchecked(buf) }; + (self.0)(str_w); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { Ok(()) } + +} + +impl Write for Writer { + + fn write(&mut self, buf: &[u8]) -> Result { + if let Some(p) = buf.iter().rposition(|b|*b == '\n' as u8) { + self.1.push_str(&String::from_utf8_lossy(&buf[..p])); + (self.0)(&self.1); + self.1.clear(); + self.1.push_str(&String::from_utf8_lossy(&buf[p..])); + } else { + // TODO add a max length for flushing + self.1.push_str(&String::from_utf8_lossy(&buf[..])); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { + (self.0)(&self.1); + self.1.clear(); + Ok(()) + } + +} + +/// Sets stdout and stderr +pub fn hook_std_io_no_buff () { + let wout = NoBuffWriter(write_out); + let werr = NoBuffWriter(write_err); + set_print(Some(Box::new(wout))); + set_panic(Some(Box::new(werr))); +} + +/// Sets stdout and stderr, use a display buffer +pub fn hook_std_io () { + let wout = Writer(write_out,String::new()); + let werr = Writer(write_err,String::new()); + set_print(Some(Box::new(wout))); + set_panic(Some(Box::new(werr))); +} + diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs index 7c3ab6441..630b9bdb7 100644 --- a/parity-wasm-compat/src/lib.rs +++ b/parity-wasm-compat/src/lib.rs @@ -16,12 +16,29 @@ //! Parity wasm compat crate. #![feature(fn_traits)] +#![feature(duration_float)] +#![feature(set_stdio)] pub mod rng; pub mod threadpool; pub mod mpsc; pub mod memmap; pub mod snappy; +pub mod time; +pub mod fs; + +#[cfg(feature = "use-tempdir")] +pub mod tempdir; +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod hook_print; +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use self::hook_print::{ hook_std_io, hook_std_io_no_buff }; + +#[cfg(not(all(target_arch = "wasm32", feature = "browser-wasm")))] +pub fn hook_std_io_no_buff () { } + +#[cfg(not(all(target_arch = "wasm32", feature = "browser-wasm")))] +pub fn hook_std_io () { } pub mod home { #[cfg(not(target_arch = "wasm32"))] @@ -37,3 +54,14 @@ pub mod home { Some(PathBuf::from("/home")) } } + +pub mod env { + #[cfg(not(target_arch = "wasm32"))] + pub use std::env::temp_dir; + #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] + use std::path::PathBuf; + #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] + pub fn temp_dir() -> PathBuf { + PathBuf::from("/temp") + } +} diff --git a/parity-wasm-compat/src/memmap.rs b/parity-wasm-compat/src/memmap.rs index b68c3ec12..1a482d9f1 100644 --- a/parity-wasm-compat/src/memmap.rs +++ b/parity-wasm-compat/src/memmap.rs @@ -17,9 +17,6 @@ //! memmap non breaking compile implementation, note that it is non functional -#[cfg(not(target_arch = "wasm32"))] -extern crate memmap; - #[cfg(not(target_arch = "wasm32"))] pub use memmap::MmapMut; diff --git a/parity-wasm-compat/src/tempdir.rs b/parity-wasm-compat/src/tempdir.rs new file mode 100644 index 000000000..b0b1e5c3c --- /dev/null +++ b/parity-wasm-compat/src/tempdir.rs @@ -0,0 +1,48 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! tempdir compat TODO is this crate still really usefull (only call to "" path)?? + +#[cfg(not(target_arch = "wasm32"))] +pub use tempdir::Tempdir; + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod tempdir_browser { + + use std::path; + use std::io; + + pub struct TempDir(pub path::PathBuf); + + impl TempDir { + pub fn new(prefix: &str) -> io::Result { + if prefix.len() > 0 { + // current use is only to get temp_dir + unimplemented!(); + } + Ok(TempDir(crate::env::temp_dir())) + } + + pub fn path(&self) -> &path::Path { + &self.0 + } + + } +} + +#[cfg(target_arch = "wasm32")] +pub use self::tempdir_browser::*; diff --git a/parity-wasm-compat/src/time.rs b/parity-wasm-compat/src/time.rs new file mode 100644 index 000000000..6460d3365 --- /dev/null +++ b/parity-wasm-compat/src/time.rs @@ -0,0 +1,142 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +//! time wasm compat (mainly access to system time through `now`) + +#[cfg(not(target_arch = "wasm32"))] +pub use std::time::{ Instant, SystemTime, Duration, SystemTimeError }; + + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +mod impl_browser { + use std::ops::{ Deref, DerefMut, Add, AddAssign, Sub, SubAssign }; + use std::fmt; + use std::time::{ Duration, SystemTime, SystemTimeError }; + + // TODO bench but might be should efficient with internal f64 + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Instant(pub Duration); + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct SystemTimeB(pub SystemTime); + + fn websys_instant() -> Duration { + let secs_f64 = web_sys::window().unwrap().performance().unwrap().now(); + Duration::from_float_secs(secs_f64) + } + + fn jssys_from_epoch() -> Duration { + let ms_f64 = js_sys::Date::now(); + Duration::from_millis(ms_f64 as u64) + } + + impl Instant { + /// see std::time::Instant; + pub fn now() -> Instant { + Instant(websys_instant()) + } + /// see std::time::Instant; + pub fn duration_since(&self, earlier: Instant) -> Duration { + self.0.sub(earlier.0) + } + /// see std::time::Instant; + pub fn elapsed(&self) -> Duration { + Instant::now().0 - self.0 + } + } + + impl Add for Instant { + type Output = Instant; + + fn add(self, other: Duration) -> Instant { + Instant(self.0.add(other)) + } + } + + impl AddAssign for Instant { + fn add_assign(&mut self, other: Duration) { + self.0 = self.0 + other; + } + } + + impl Sub for Instant { + type Output = Instant; + + fn sub(self, other: Duration) -> Instant { + Instant(self.0.sub(other)) + } + } + + impl SubAssign for Instant { + fn sub_assign(&mut self, other: Duration) { + self.0 = self.0 - other; + } + } + + impl Sub for Instant { + type Output = Duration; + + fn sub(self, other: Instant) -> Duration { + self.duration_since(other) + } + } + + impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } + } + + impl SystemTimeB { + /// see std::time::SystemTime; + pub const UNIX_EPOCH: SystemTimeB = SystemTimeB(SystemTime::UNIX_EPOCH); + + /// see std::time::SystemTime; + pub fn now() -> SystemTimeB { + let now = SystemTime::UNIX_EPOCH + jssys_from_epoch(); + SystemTimeB(now) + } + + /// see std::time::SystemTime; + pub fn elapsed(&self) -> Result { + SystemTimeB::now().duration_since(self.0) + } + } + + impl Deref for SystemTimeB { + type Target = SystemTime; + + fn deref(&self) -> &SystemTime { + &self.0 + } + } + impl DerefMut for SystemTimeB { + fn deref_mut(&mut self) -> &mut SystemTime { + &mut self.0 + } + } + + impl fmt::Debug for SystemTimeB { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } + } +} + +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use self::impl_browser::{ Instant, SystemTimeB as SystemTime }; +#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] +pub use std::time::{ Duration }; From 85707f9c1802d09943f263136980cbd94d523ce5 Mon Sep 17 00:00:00 2001 From: cheme Date: Wed, 7 Nov 2018 15:28:51 +0100 Subject: [PATCH 20/39] Keep only crypto changes. --- Cargo.toml | 1 - parity-wasm-compat/Cargo.toml | 33 -- parity-wasm-compat/README.md | 11 - parity-wasm-compat/src/fs/fs_browser.rs | 373 ------------------ parity-wasm-compat/src/fs/mod.rs | 34 -- parity-wasm-compat/src/hook_print.rs | 90 ----- parity-wasm-compat/src/lib.rs | 67 ---- parity-wasm-compat/src/memmap.rs | 73 ---- parity-wasm-compat/src/mpsc/mod.rs | 32 -- .../src/mpsc/mpsc_browser_single.rs | 65 --- parity-wasm-compat/src/rng/mod.rs | 32 -- parity-wasm-compat/src/rng/rng_browser.rs | 78 ---- parity-wasm-compat/src/snappy.rs | 92 ----- parity-wasm-compat/src/tempdir.rs | 48 --- parity-wasm-compat/src/threadpool/mod.rs | 32 -- .../threadpool/threadpool_browser_single.rs | 95 ----- parity-wasm-compat/src/time.rs | 142 ------- 17 files changed, 1298 deletions(-) delete mode 100644 parity-wasm-compat/Cargo.toml delete mode 100644 parity-wasm-compat/README.md delete mode 100644 parity-wasm-compat/src/fs/fs_browser.rs delete mode 100644 parity-wasm-compat/src/fs/mod.rs delete mode 100644 parity-wasm-compat/src/hook_print.rs delete mode 100644 parity-wasm-compat/src/lib.rs delete mode 100644 parity-wasm-compat/src/memmap.rs delete mode 100644 parity-wasm-compat/src/mpsc/mod.rs delete mode 100644 parity-wasm-compat/src/mpsc/mpsc_browser_single.rs delete mode 100644 parity-wasm-compat/src/rng/mod.rs delete mode 100644 parity-wasm-compat/src/rng/rng_browser.rs delete mode 100644 parity-wasm-compat/src/snappy.rs delete mode 100644 parity-wasm-compat/src/tempdir.rs delete mode 100644 parity-wasm-compat/src/threadpool/mod.rs delete mode 100644 parity-wasm-compat/src/threadpool/threadpool_browser_single.rs delete mode 100644 parity-wasm-compat/src/time.rs diff --git a/Cargo.toml b/Cargo.toml index 88365ec7a..0d6dbe4c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,5 +18,4 @@ members = [ "trie-standardmap", "triehash", "uint", - "parity-wasm-compat" ] diff --git a/parity-wasm-compat/Cargo.toml b/parity-wasm-compat/Cargo.toml deleted file mode 100644 index e2fbeaf38..000000000 --- a/parity-wasm-compat/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "parity-wasm-compat" -version = "0.1.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] -repository = "https://github.com/paritytech/parity-common" -edition = "2018" - -[lib] -crate-type = ["cdylib", "rlib"] - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -rand = "0.4" -threadpool = "1.7" -home = "0.3" -memmap = "0.7" -parity-snappy = { version = "0.1" } -tempdir = {version="0.3", optional = true} - -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen = { version = "0.2", optional = true } -web-sys = { version = "0.3", features = ["Window", "Crypto", "Performance", "console"], optional = true } -js-sys = { version = "0.3", optional = true} - -rand = "0.5" -snap = "0.2" - -[features] -default=["browser-wasm"] -browser-wasm=["web-sys","js-sys","wasm-bindgen"] -extrinsic-wasm=[] -node-wasm=[] -use-tempdir=["tempdir"] diff --git a/parity-wasm-compat/README.md b/parity-wasm-compat/README.md deleted file mode 100644 index b1f07db93..000000000 --- a/parity-wasm-compat/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# parity-wasm-compat - -Compatibility crate for different wasm output, and to keep existing non wasm usage. - -This is a crate hosting common abstraction over multiple missing stdlib compatibility. - -Those functionality are mainly here until better alternative are published or usable. - -This crate is mainly here to avoid code redundancy and focus on opinionated parity related usage (for instance browser wasm thread could simply be a synchronous execution : that obviously only works for a small category of code and is not equivalent). - - diff --git a/parity-wasm-compat/src/fs/fs_browser.rs b/parity-wasm-compat/src/fs/fs_browser.rs deleted file mode 100644 index 25b19bd95..000000000 --- a/parity-wasm-compat/src/fs/fs_browser.rs +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! fs compatibility (very limited) - - -use std::io::{ self, Read, Write, Seek, SeekFrom }; -use std::path::Path; -use wasm_bindgen::prelude::*; - -// put in module env for now -#[wasm_bindgen(module = "env")] -extern "C" { - - pub type JsFile; - - #[wasm_bindgen(catch)] - fn open_browserfs(path: &str, option: i32) -> Result; - - #[wasm_bindgen(catch)] - fn read_browserfs(jsfile: &JsFile, buff: *mut u8, len: u32) -> Result; - - #[wasm_bindgen(catch)] - fn write_browserfs(jsfile: &JsFile, buff: *const u8, len: u32) -> Result; - - #[wasm_bindgen(catch)] - fn flush_write_browserfs(jsfile: &JsFile) -> Result<(), JsValue>; - - #[wasm_bindgen(catch)] - fn set_len_browserfs(jsfile: &JsFile, len: u64) -> Result<(), JsValue>; - - fn close_browserfs(jsfile: &JsFile); - - #[wasm_bindgen(catch)] - fn seek_browserfs(jsfile: &JsFile, mov: i64) -> Result; - - fn seek_browserfs_from_start(jsfile: &JsFile, mov: u32) -> u32; - - #[wasm_bindgen(catch)] - fn seek_browserfs_from_end(jsfile: &JsFile, mov: i64) -> Result; - - fn len_browserfs(jsfile: &JsFile) -> u64; - -} - -pub struct File(pub JsFile); - -#[allow(non_camel_case_types)] -type c_int = i32; - -#[allow(non_camel_case_types)] -type mode_t = u32; - -mod libc { - use super::c_int; - // reexport unix libc constant for file - // - pub const O_RDONLY: c_int = 0; - pub const O_WRONLY: c_int = 1; - pub const O_RDWR: c_int = 2; - - pub const O_APPEND: c_int = 1024; - - pub const O_CREAT: c_int = 64; - pub const O_EXCL: c_int = 128; - pub const O_TRUNC: c_int = 512; - - pub const EINVAL : c_int = 22; -} -/// straight copy of unix code plus create and new -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: mode_t, -} - - -impl OpenOptions { - /// only non copied function from unix code - pub fn open>(&self, path: P) -> io::Result { - let tag = self.get_access_mode()? | - self.get_creation_mode()? | - (self.custom_flags as c_int); - open_browserfs(path.as_ref().to_str().expect("input from browser in utf8"), tag) - .map_err(|jsval|io::Error::new(io::ErrorKind::Other, format!("could not open file in browser: {:?}",jsval))) - .map(|jsfile|File(jsfile)) - - } - - - /// see unix openoption - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - /// see unix openoption - pub fn read(mut self, read: bool) -> Self { self.read = read; self } - /// see unix openoption - pub fn write(mut self, write: bool) -> Self { self.write = write; self } - /// see unix openoption - pub fn append(mut self, append: bool) -> Self { self.append = append; self } - /// see unix openoption - pub fn truncate(mut self, truncate: bool) -> Self { self.truncate = truncate; self } - /// see unix openoption - pub fn create(mut self, create: bool) -> Self { self.create = create; self } - /// see unix openoption - pub fn create_new(mut self, create_new: bool) -> Self { self.create_new = create_new; self } - - /// see unix openoption - pub fn custom_flags(mut self, flags: i32) -> Self { self.custom_flags = flags; self } - /// warning curently not used TODO usable in node fs - pub fn mode(mut self, mode: u32) -> Self { self.mode = mode as mode_t; self } - - /// see unix openoption - fn get_access_mode(&self) -> io::Result { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(libc::O_RDONLY), - (false, true, false) => Ok(libc::O_WRONLY), - (true, true, false) => Ok(libc::O_RDWR), - (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), - (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), - (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)), - } - } - - /// see unix openoption - fn get_creation_mode(&self) -> io::Result { - match (self.write, self.append) { - (true, false) => {} - (false, false) => - if self.truncate || self.create || self.create_new { - return Err(io::Error::from_raw_os_error(libc::EINVAL)); - }, - (_, true) => - if self.truncate && !self.create_new { - return Err(io::Error::from_raw_os_error(libc::EINVAL)); - }, - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => libc::O_CREAT, - (false, true, false) => libc::O_TRUNC, - (true, true, false) => libc::O_CREAT | libc::O_TRUNC, - (_, _, true) => libc::O_CREAT | libc::O_EXCL, - }) - } -} - -/* -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, -} -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - } - } - - pub fn read(&mut self, read: bool) { self.read = read; } - pub fn write(&mut self, write: bool) { self.write = write; } - pub fn append(&mut self, append: bool) { self.append = append; } - pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; } - pub fn create(&mut self, create: bool) { self.create = create; } - pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; } - - // mapping from https://nodejs.org/api/fs.html#fs_file_system_flags - fn get_node_fs_tag(&self) -> io::Result<&str> { - const tag_r : &str = "r"; // reading, should exist - const tag_rp : &str = "r+"; // reading, should exist, + write - const tag_w : &str = "w"; // writing, truncate if exist and create if don't - const tag_wx : &str = "wx"; // writing, truncate if exist and create if don't, fail if exist - const tag_wp : &str = "w+"; // writing, truncate if exist and create if don't - const tag_wxp : &str = "wx+"; // writing, truncate if exist and create if don't, fail if exist - const tag_a : &str = "a"; // append , create if does not exist - const tag_ax : &str = "ax"; // append , create if does not exist, fail if exist - const tag_ap : &str = "a+"; // append , create if does not exist - const tag_axp : &str = "ax+"; // append , create if does not exist, fail if exist - match (self.read, self.write, self.append, self.truncate, self.create, self.create_new) { - (true, false, false, false, false, false) => Ok(&tag_r), - (true, true, false, false, false, false) => Ok(&tag_rp), - (false, true, false, true, true, false) => Ok(&tag_w), - (false, true, false, true, true, true) => Ok(&tag_wx), - (true, true, false, true, true, false) => Ok(&tag_wp), - (true, true, false, true, true, true) => Ok(&tag_wxp), - (false, _, true, false, true, false) => Ok(&tag_a), - (false, _, true, false, true, true) => Ok(&tag_ax), - (true, _, true, false, true, false) => Ok(&tag_ap), - (true, _, true, false, true, true) => Ok(&tag_axp), - _ => Err(io::Error::new(io::ErrorKind::Other, "unimplemented or non allowed openoption configuration")), - } - } -} -*/ -impl File { - - /// see std::fs::File - pub fn open>(path: P) -> io::Result { - open_browserfs(path.as_ref().to_str().expect("input from browser in utf8"), 0) - .map_err(|jsval|io::Error::new(io::ErrorKind::Other, format!("could not open file in browser: {:?}",jsval))) - .map(|jsfile|File(jsfile)) - } - - fn inner_read(&self, buf: &mut [u8]) -> io::Result { - let l = buf.len(); - match read_browserfs(&self.0, buf.as_mut_ptr(), l as u32) { - Ok(n) => Ok(n as usize), - Err(jsval) => Err(io::Error::new( - io::ErrorKind::Other, format!("could not read from file in browser: {:?}",jsval) - )), - } - } - - fn inner_write(&self, buf: &[u8]) -> io::Result { - let l = buf.len(); - match write_browserfs(&self.0, buf.as_ptr(), l as u32) { - Ok(n) => Ok(n as usize), - Err(jsval) => Err(io::Error::new( - io::ErrorKind::Other, format!("could not write in file in browser: {:?}",jsval) - )), - } - } - - fn inner_flush(&self) -> io::Result<()> { - match flush_write_browserfs(&self.0) { - Ok(n) => Ok(n), - Err(jsval) => Err(io::Error::new( - io::ErrorKind::Other, format!("error when flushing file in browser: {:?}",jsval) - )), - } - } - - // Note that if we stored jsfile in rust memory (doable (just get the fd with open), probably better design), - // we would not need to call js (except to get length for end) here - // TODO redesign if this wasm compat get used (and choice of memfs is ok), at least it - // demonstrate wasmbindgen capability (but it is a waste here). Will get a slight issue with - // mutability - fn inner_seek(&self, pos: SeekFrom) -> io::Result { - match match pos { - SeekFrom::Current(nb) => seek_browserfs(&self.0, nb), - SeekFrom::Start(nb) => Ok(seek_browserfs_from_start(&self.0, nb as u32) as u32), - SeekFrom::End(nb) => seek_browserfs_from_end(&self.0, nb), - } { - Ok(n) => Ok(n as u64), - Err(jsval) => Err(io::Error::new( - io::ErrorKind::Other, format!("seek to under zero position: {:?}",jsval) - )), - } - } - - pub fn set_len(&self, size: u64) -> io::Result<()> { - match set_len_browserfs(&self.0, size) { - Ok(n) => Ok(n), - Err(jsval) => Err(io::Error::new( - io::ErrorKind::Other, format!("error changing file length in browser: {:?}",jsval) - )), - } - } - - /// warning non conform use : would need to query stat as metada, TODO keep it with not many use - /// case - pub fn metadata(&self) -> io::Result<&Self> { - Ok(self) - } - - /// from metadata use case, move it to metadata if using stat value as metadata - /// TODO this is bad semantic indeed (can return an error) - pub fn len(&self) -> u64 { - len_browserfs(&self.0) - } - -} -impl Read for File { - - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner_read(buf) - } - -} - -impl Write for File { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner_write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner_flush() - } -} - -impl Seek for File { - - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner_seek(pos) - } -} - -impl Drop for File { - fn drop(&mut self) { - close_browserfs(&self.0); - } -} - -impl<'a> Read for &'a File { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner_read(buf) - } -} - -impl<'a> Write for &'a File { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner_write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner_flush() - } -} - -impl<'a> Seek for &'a File { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner_seek(pos) - } -} - - diff --git a/parity-wasm-compat/src/fs/mod.rs b/parity-wasm-compat/src/fs/mod.rs deleted file mode 100644 index 20dafc4ec..000000000 --- a/parity-wasm-compat/src/fs/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! File compatibility, at this point it is only to allow very specific case (no directory -//! management, `is_file` defaulting to true is good for it). And probably only our last usecase -//! (open file and read_to_end). - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod fs_browser; - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use self::fs_browser::*; - -#[cfg(not(target_arch = "wasm32"))] -mod fs_crate { - pub use std::fs::{ File, OpenOptions }; -} - -#[cfg(not(target_arch = "wasm32"))] -pub use self::fs_crate::*; diff --git a/parity-wasm-compat/src/hook_print.rs b/parity-wasm-compat/src/hook_print.rs deleted file mode 100644 index 7d41c2132..000000000 --- a/parity-wasm-compat/src/hook_print.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! Hook to display stdout and stderr as websys console calls - -use std::io::{ Write, Result, set_panic, set_print }; -use web_sys::console; -use wasm_bindgen::JsValue; -use js_sys::Array; - -fn write_out(v: &str) { - if v.len() > 0 { - console::log(&Array::of1(&JsValue::from(v))) - } -} -fn write_err(v: &str) { - if v.len() > 0 { - console::warn(&Array::of1(&JsValue::from(v))) - } -} - -struct Writer(pub fn(&str), pub String); - -struct NoBuffWriter(fn(&str)); - -impl Write for NoBuffWriter { - - fn write(&mut self, buf: &[u8]) -> Result { - let str_w = unsafe { std::str::from_utf8_unchecked(buf) }; - (self.0)(str_w); - Ok(buf.len()) - } - - fn flush(&mut self) -> Result<()> { Ok(()) } - -} - -impl Write for Writer { - - fn write(&mut self, buf: &[u8]) -> Result { - if let Some(p) = buf.iter().rposition(|b|*b == '\n' as u8) { - self.1.push_str(&String::from_utf8_lossy(&buf[..p])); - (self.0)(&self.1); - self.1.clear(); - self.1.push_str(&String::from_utf8_lossy(&buf[p..])); - } else { - // TODO add a max length for flushing - self.1.push_str(&String::from_utf8_lossy(&buf[..])); - } - Ok(buf.len()) - } - - fn flush(&mut self) -> Result<()> { - (self.0)(&self.1); - self.1.clear(); - Ok(()) - } - -} - -/// Sets stdout and stderr -pub fn hook_std_io_no_buff () { - let wout = NoBuffWriter(write_out); - let werr = NoBuffWriter(write_err); - set_print(Some(Box::new(wout))); - set_panic(Some(Box::new(werr))); -} - -/// Sets stdout and stderr, use a display buffer -pub fn hook_std_io () { - let wout = Writer(write_out,String::new()); - let werr = Writer(write_err,String::new()); - set_print(Some(Box::new(wout))); - set_panic(Some(Box::new(werr))); -} - diff --git a/parity-wasm-compat/src/lib.rs b/parity-wasm-compat/src/lib.rs deleted file mode 100644 index 630b9bdb7..000000000 --- a/parity-wasm-compat/src/lib.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Parity wasm compat crate. -#![feature(fn_traits)] -#![feature(duration_float)] -#![feature(set_stdio)] - -pub mod rng; -pub mod threadpool; -pub mod mpsc; -pub mod memmap; -pub mod snappy; -pub mod time; -pub mod fs; - -#[cfg(feature = "use-tempdir")] -pub mod tempdir; -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod hook_print; -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use self::hook_print::{ hook_std_io, hook_std_io_no_buff }; - -#[cfg(not(all(target_arch = "wasm32", feature = "browser-wasm")))] -pub fn hook_std_io_no_buff () { } - -#[cfg(not(all(target_arch = "wasm32", feature = "browser-wasm")))] -pub fn hook_std_io () { } - -pub mod home { - #[cfg(not(target_arch = "wasm32"))] - extern crate home; - #[cfg(not(target_arch = "wasm32"))] - pub use home::home_dir; - - #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] - use std::path::PathBuf; - #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] - pub fn home_dir() -> Option { - // need a dummy dir for whatever browser mapping we use - Some(PathBuf::from("/home")) - } -} - -pub mod env { - #[cfg(not(target_arch = "wasm32"))] - pub use std::env::temp_dir; - #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] - use std::path::PathBuf; - #[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] - pub fn temp_dir() -> PathBuf { - PathBuf::from("/temp") - } -} diff --git a/parity-wasm-compat/src/memmap.rs b/parity-wasm-compat/src/memmap.rs deleted file mode 100644 index 1a482d9f1..000000000 --- a/parity-wasm-compat/src/memmap.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! memmap non breaking compile implementation, note that it is non functional - -#[cfg(not(target_arch = "wasm32"))] -pub use memmap::MmapMut; - -#[cfg(target_arch = "wasm32")] -pub struct MmapMut; - -#[cfg(target_arch = "wasm32")] -use std::io::{ErrorKind, Result}; - -#[cfg(target_arch = "wasm32")] -use std::fs::File; - -#[cfg(target_arch = "wasm32")] -use std::ops::{Deref, DerefMut}; - -#[cfg(target_arch = "wasm32")] -impl MmapMut { - - pub unsafe fn map_mut(_file: &File) -> Result { - Err(ErrorKind::Other.into()) - } - - pub fn flush(&self) -> Result<()> { - Err(ErrorKind::Other.into()) - } -} - - -#[cfg(target_arch = "wasm32")] -impl Deref for MmapMut { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &[u8] { - unimplemented!() - } -} - -#[cfg(target_arch = "wasm32")] -impl DerefMut for MmapMut { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unimplemented!() - } -} - -#[cfg(target_arch = "wasm32")] -impl AsRef<[u8]> for MmapMut { - #[inline] - fn as_ref(&self) -> &[u8] { - unimplemented!() - } -} - diff --git a/parity-wasm-compat/src/mpsc/mod.rs b/parity-wasm-compat/src/mpsc/mod.rs deleted file mode 100644 index 0859686ae..000000000 --- a/parity-wasm-compat/src/mpsc/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! mpsc compatibility - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod mpsc_browser_single; - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use self::mpsc_browser_single::*; - -#[cfg(not(target_arch = "wasm32"))] -mod mpsc_crate { - pub use std::sync::mpsc::{ sync_channel, SyncSender, Receiver }; // need build then from pool max_count and execute -} - -#[cfg(not(target_arch = "wasm32"))] -pub use self::mpsc_crate::*; diff --git a/parity-wasm-compat/src/mpsc/mpsc_browser_single.rs b/parity-wasm-compat/src/mpsc/mpsc_browser_single.rs deleted file mode 100644 index 905f2935a..000000000 --- a/parity-wasm-compat/src/mpsc/mpsc_browser_single.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! mpsc single thread compatibility (very minimal, could only run on particular conditions for -//! instance adding result from threads) - -use std::rc::Rc; -use std::cell::RefCell; -use std::sync::mpsc::{ SendError, RecvError }; -use std::collections::VecDeque; - -pub struct SyncSender(Rc>>); - -unsafe impl Send for SyncSender {} - -impl Clone for SyncSender { - fn clone(&self) -> SyncSender { - SyncSender(self.0.clone()) - } -} - - -pub struct Receiver(Rc>>); - -pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { - let v = Rc::new(RefCell::new(VecDeque::with_capacity(bound))); - (SyncSender(v.clone()), Receiver(v)) -} - -impl SyncSender { - - pub fn send(&self, t: T) -> Result<(), SendError> { - self.0.borrow_mut().push_front(t); - Ok(()) - } - -} - - -impl Receiver { - - pub fn recv(&self) -> Result { - if let Some(t) = self.0.borrow_mut().pop_front() { - Ok(t) - } else { - Err(RecvError) - } - } - -} - diff --git a/parity-wasm-compat/src/rng/mod.rs b/parity-wasm-compat/src/rng/mod.rs deleted file mode 100644 index 34458b0f6..000000000 --- a/parity-wasm-compat/src/rng/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! rng alternative implementation, note that future version of rand crate will probably cover that -//! (at the time it uses stdweb and emscripten only). -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod rng_browser; - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use self::rng_browser::OsRng; - -#[cfg(not(target_arch = "wasm32"))] -mod rng_std { - pub use rand::OsRng; -} - -#[cfg(not(target_arch = "wasm32"))] -pub use self::rng_std::OsRng; diff --git a/parity-wasm-compat/src/rng/rng_browser.rs b/parity-wasm-compat/src/rng/rng_browser.rs deleted file mode 100644 index f032ab335..000000000 --- a/parity-wasm-compat/src/rng/rng_browser.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! rng adapter for wasm in browser (using websys crate) - -use web_sys::Crypto; -use rand::{ CryptoRng, RngCore, Error, ErrorKind }; -use std::fmt; -use std::mem::transmute; - -#[derive(Clone)] -pub struct OsRng; - -impl fmt::Debug for OsRng { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "OsRng using webcrypto rng source".fmt(f) - } -} - -impl OsRng { - pub fn new() -> Result { - Ok(OsRng) - } -} - -impl CryptoRng for OsRng {} - -// current buffer usage is quite ineficient -impl RngCore for OsRng { - - fn next_u32(&mut self) -> u32 { - let result: u32 = 0; - let mut buf: [u8; 4] = unsafe { transmute(result) }; - let crypto: Crypto = web_sys::window().unwrap().crypto().unwrap(); - crypto.get_random_values_with_u8_array(&mut buf[..]).expect("Not able to operate without random source."); - unsafe { transmute(buf) } - } - - fn next_u64(&mut self) -> u64 { - let result: u64 = 0; - let mut buf: [u8; 8] = unsafe { transmute(result) }; - let crypto: Crypto = web_sys::window().unwrap().crypto().unwrap(); - crypto.get_random_values_with_u8_array(&mut buf[..]).expect("Not able to operate without random source."); - unsafe { transmute(buf) } - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - let crypto: Crypto = web_sys::window().unwrap().crypto().unwrap(); - crypto.get_random_values_with_u8_array(dest).expect("Not able to operate without random source."); - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - if let Some(window) = web_sys::window() { - let crypto = window.crypto() - .map_err(|_jsval|Error::new(ErrorKind::Unexpected, "Error accessing webcrypto in browser"))?; - crypto.get_random_values_with_u8_array(dest) - .map_err(|_jsval|Error::new(ErrorKind::Unexpected, "Error getting random value from webcrypto"))?; - Ok(()) - } else { - Err(Error::new(ErrorKind::Unavailable, "error getting window")) - } - } - -} - diff --git a/parity-wasm-compat/src/snappy.rs b/parity-wasm-compat/src/snappy.rs deleted file mode 100644 index d410288b6..000000000 --- a/parity-wasm-compat/src/snappy.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Use rust native snappy for wasm32 - - -#[cfg(target_arch = "wasm32")] -extern crate snap; - -#[cfg(not(target_arch = "wasm32"))] -extern crate parity_snappy; - -#[cfg(not(target_arch = "wasm32"))] -pub use parity_snappy as snappy; - - -#[cfg(target_arch = "wasm32")] -pub mod snappy { - - use std::fmt; - - #[inline] - pub fn max_compressed_len(len: usize) -> usize { - snap::max_compress_len(len) - } - pub fn decompressed_len(compressed: &[u8]) -> Result { - Ok(snap::decompress_len(compressed)?) - } - pub fn compress(input: &[u8]) -> Vec { - let mut enc = snap::Encoder::new(); - enc.compress_vec(input).expect("No failure on compression") - } - // TODO this proto is not really efficient, snappy compression should use inline buffered - // see snap writer and reader trait (plus return error) - pub fn compress_into(input: &[u8], output: &mut Vec) -> usize { - let mut enc = snap::Encoder::new(); - let l = max_compressed_len(input.len()); - if output.len() < l { - output.resize(l,0); - } - enc.compress(input, &mut output[..]).expect("No failure on compression") - } - pub fn decompress(input: &[u8]) -> Result, InvalidInput> { - let mut dec = snap::Decoder::new(); - Ok(dec.decompress_vec(input)?) - } - // TODO this proto is not really efficient, snappy compression should use inline buffered - // This is bad it build huge buffer - pub fn decompress_into(input: &[u8], output: &mut Vec) -> Result { - let mut dec = snap::Decoder::new(); - let l = decompressed_len(input)?; - if output.len() < l { - output.resize(l,0); - } - Ok(dec.decompress(input, &mut output[..])?) - } - - #[derive(Debug)] - pub struct InvalidInput; - - impl std::error::Error for InvalidInput { - fn description(&self) -> &str { - "Attempted snappy decompression with invalid input" - } - } - - impl fmt::Display for InvalidInput { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Attempted snappy decompression with invalid input") - } - } - - impl std::convert::From for InvalidInput { - fn from(_: snap::Error) -> Self { - InvalidInput - } - } - -} diff --git a/parity-wasm-compat/src/tempdir.rs b/parity-wasm-compat/src/tempdir.rs deleted file mode 100644 index b0b1e5c3c..000000000 --- a/parity-wasm-compat/src/tempdir.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! tempdir compat TODO is this crate still really usefull (only call to "" path)?? - -#[cfg(not(target_arch = "wasm32"))] -pub use tempdir::Tempdir; - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod tempdir_browser { - - use std::path; - use std::io; - - pub struct TempDir(pub path::PathBuf); - - impl TempDir { - pub fn new(prefix: &str) -> io::Result { - if prefix.len() > 0 { - // current use is only to get temp_dir - unimplemented!(); - } - Ok(TempDir(crate::env::temp_dir())) - } - - pub fn path(&self) -> &path::Path { - &self.0 - } - - } -} - -#[cfg(target_arch = "wasm32")] -pub use self::tempdir_browser::*; diff --git a/parity-wasm-compat/src/threadpool/mod.rs b/parity-wasm-compat/src/threadpool/mod.rs deleted file mode 100644 index 5c517bd9f..000000000 --- a/parity-wasm-compat/src/threadpool/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! threadpool compatibility - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod threadpool_browser_single; - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use self::threadpool_browser_single::{ Builder, ThreadPool }; - -#[cfg(not(target_arch = "wasm32"))] -mod threadpool_crate { - pub use threadpool::{ Builder, ThreadPool }; // need build then from pool max_count and execute -} - -#[cfg(not(target_arch = "wasm32"))] -pub use self::threadpool_crate::*; diff --git a/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs b/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs deleted file mode 100644 index d535ea9f3..000000000 --- a/parity-wasm-compat/src/threadpool/threadpool_browser_single.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Threadpool forcing single thread synchronous usage. -//! Very likely to break existing code (implicit switch between asynchronous and synchronous -//! paradigm), because we do not ensure it runs only for unique thread configuration. -//! -//! A variant of this execution should allow running suspendable execution to run more use case. -//! - -#[derive(Clone, Default)] -pub struct Builder(Option); - -pub struct ThreadPool(Option); - - -impl Builder { - pub fn new() -> Builder { - Builder(None) - } - - pub fn num_threads(self, _num_threads: usize) -> Builder { - // do nothing (no error either (flexibility for usage in existing code)). - self - } - - - pub fn thread_name(mut self, name: String) -> Builder { - self.0 = Some(name); - self - } - - pub fn thread_stack_size(self, _size: usize) -> Builder { - // unmanaged - self - } - - pub fn build(self) -> ThreadPool { - ThreadPool(self.0) - } - -} - -impl ThreadPool { - - pub fn new(num_threads: usize) -> ThreadPool { - Builder::new().num_threads(num_threads).build() - } - - pub fn with_name(name: String, num_threads: usize) -> ThreadPool { - Builder::new().thread_name(name).num_threads(num_threads).build() - } - - pub fn queued_count(&self) -> usize { - // cannot queue with synch ex - 0 - } - - pub fn active_count(&self) -> usize { - // cannot query running with non suspendable synch ex - 0 - } - - pub fn max_count(&self) -> usize { - // single thread - 1 - } - - pub fn panic_count(&self) -> usize { 0 } - - pub fn set_num_threads(&mut self, _num_threads: usize) { } - - pub fn join(&self) { } - - pub fn execute(&self, job: F) - where - F: FnOnce() + Send + 'static, - { - job.call_once(()) - } - -} diff --git a/parity-wasm-compat/src/time.rs b/parity-wasm-compat/src/time.rs deleted file mode 100644 index 6460d3365..000000000 --- a/parity-wasm-compat/src/time.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -//! time wasm compat (mainly access to system time through `now`) - -#[cfg(not(target_arch = "wasm32"))] -pub use std::time::{ Instant, SystemTime, Duration, SystemTimeError }; - - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -mod impl_browser { - use std::ops::{ Deref, DerefMut, Add, AddAssign, Sub, SubAssign }; - use std::fmt; - use std::time::{ Duration, SystemTime, SystemTimeError }; - - // TODO bench but might be should efficient with internal f64 - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Instant(pub Duration); - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTimeB(pub SystemTime); - - fn websys_instant() -> Duration { - let secs_f64 = web_sys::window().unwrap().performance().unwrap().now(); - Duration::from_float_secs(secs_f64) - } - - fn jssys_from_epoch() -> Duration { - let ms_f64 = js_sys::Date::now(); - Duration::from_millis(ms_f64 as u64) - } - - impl Instant { - /// see std::time::Instant; - pub fn now() -> Instant { - Instant(websys_instant()) - } - /// see std::time::Instant; - pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.sub(earlier.0) - } - /// see std::time::Instant; - pub fn elapsed(&self) -> Duration { - Instant::now().0 - self.0 - } - } - - impl Add for Instant { - type Output = Instant; - - fn add(self, other: Duration) -> Instant { - Instant(self.0.add(other)) - } - } - - impl AddAssign for Instant { - fn add_assign(&mut self, other: Duration) { - self.0 = self.0 + other; - } - } - - impl Sub for Instant { - type Output = Instant; - - fn sub(self, other: Duration) -> Instant { - Instant(self.0.sub(other)) - } - } - - impl SubAssign for Instant { - fn sub_assign(&mut self, other: Duration) { - self.0 = self.0 - other; - } - } - - impl Sub for Instant { - type Output = Duration; - - fn sub(self, other: Instant) -> Duration { - self.duration_since(other) - } - } - - impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } - - impl SystemTimeB { - /// see std::time::SystemTime; - pub const UNIX_EPOCH: SystemTimeB = SystemTimeB(SystemTime::UNIX_EPOCH); - - /// see std::time::SystemTime; - pub fn now() -> SystemTimeB { - let now = SystemTime::UNIX_EPOCH + jssys_from_epoch(); - SystemTimeB(now) - } - - /// see std::time::SystemTime; - pub fn elapsed(&self) -> Result { - SystemTimeB::now().duration_since(self.0) - } - } - - impl Deref for SystemTimeB { - type Target = SystemTime; - - fn deref(&self) -> &SystemTime { - &self.0 - } - } - impl DerefMut for SystemTimeB { - fn deref_mut(&mut self) -> &mut SystemTime { - &mut self.0 - } - } - - impl fmt::Debug for SystemTimeB { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } -} - -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use self::impl_browser::{ Instant, SystemTimeB as SystemTime }; -#[cfg(all(target_arch = "wasm32", feature = "browser-wasm"))] -pub use std::time::{ Duration }; From 6ab9fb9f6237015655d04eb695a686eef4f3385a Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 8 Nov 2018 11:25:17 +0100 Subject: [PATCH 21/39] moving mem from parity-ethereum to parity-common and generalizing Clear_on_drop usage. --- mem/Cargo.toml | 11 ++++ mem/src/lib.rs | 74 +++++++++++++++++++++++ parity-crypto/Cargo.toml | 14 +++-- parity-crypto/src/lib.rs | 10 ++++ parity-crypto/src/secp256k1.rs | 95 +++++++++++++++++++++--------- parity-crypto/src/secp256k1_alt.rs | 33 +++++++++-- 6 files changed, 200 insertions(+), 37 deletions(-) create mode 100644 mem/Cargo.toml create mode 100644 mem/src/lib.rs diff --git a/mem/Cargo.toml b/mem/Cargo.toml new file mode 100644 index 000000000..343858b74 --- /dev/null +++ b/mem/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "mem" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +clear_on_drop = "0.2.3" + +[features] +# when activated mem is removed through volatile primitive instead of clear_on_drop crate +volatile-erase = [] diff --git a/mem/src/lib.rs b/mem/src/lib.rs new file mode 100644 index 000000000..edde14bfe --- /dev/null +++ b/mem/src/lib.rs @@ -0,0 +1,74 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +extern crate clear_on_drop as cod; + +use std::ops::{Deref, DerefMut}; + +#[cfg(feature = "volatile-erase")] +use std::ptr; + +#[cfg(not(feature = "volatile-erase"))] +pub use cod::clear::Clear; + +/// reexport clear_on_drop crate +pub mod clear_on_drop { + pub use cod::*; +} + +/// Wrapper to zero out memory when dropped. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Memzero> { + mem: T, +} + +impl> From for Memzero { + fn from(mem: T) -> Memzero { + Memzero { mem } + } +} + +#[cfg(feature = "volatile-erase")] +impl> Drop for Memzero { + fn drop(&mut self) { + unsafe { + for byte_ref in self.mem.as_mut() { + ptr::write_volatile(byte_ref, 0) + } + } + } +} + +#[cfg(not(feature = "volatile-erase"))] +impl> Drop for Memzero { + fn drop(&mut self) { + self.as_mut().clear(); + } +} + +impl> Deref for Memzero { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.mem + } +} + +impl> DerefMut for Memzero { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.mem + } +} diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 8c28aa3c6..44b72b7b5 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["rename-dependency"] - [package] name = "parity-crypto" version = "0.2.0" @@ -20,6 +18,7 @@ aes = "0.2.0" aes-ctr = "0.1.0" block-modes = "0.1.0" lazy_static = "1.0" # for secp +mem = { path = "../mem" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.13" @@ -28,13 +27,18 @@ rand = "0.4" [target.'cfg(target_arch = "wasm32")'.dependencies] hmac = "0.7" -subtle = { version = "1.0", features = ["nightly"] } -libsecp256k1 = { version = "0.1", package = "libsecp256k1" } +subtle = { version = "1.0" } +# libsecp256k1 = { version = "0.1", package = "libsecp256k1" } // requires 'rename-dependency' in stable +libsecp256k1 = { path = "./libsecp256k1" } rand = "0.5" pbkdf2 = { version = "0.3", default-features = false } [dev-dependencies] hmac = "0.7" -libsecp256k1 = { version = "0.1", package = "libsecp256k1" } +# libsecp256k1 = { version = "0.1", package = "libsecp256k1" } // requires 'rename-dependency' in stable +libsecp256k1 = { path = "./libsecp256k1" } pbkdf2 = { version = "0.3", default-features = false } +[features] +nightly = ["subtle/nightly"] +volatile-erase = ["mem/volatile-erase"] diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 569419a4a..55f4dae16 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -32,8 +32,17 @@ extern crate digest as rdigest; extern crate aes as raes; extern crate aes_ctr; extern crate block_modes; +extern crate mem; +/// reexport clear_on_drop crate +pub mod clear_on_drop { + pub use mem::clear_on_drop::*; +} + +/// reexport `Memzero` from `mem` +pub use mem::Memzero; +pub mod traits; pub mod aes; #[cfg(not(target_arch = "wasm32"))] pub mod aes_gcm; @@ -55,6 +64,7 @@ pub mod secp256k1; #[cfg(all(not(target_arch = "wasm32"), test))] pub mod secp256k1_alt; + #[path = "secp256k1_alt.rs"] #[cfg(target_arch = "wasm32")] pub mod secp256k1; diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index 78b801af9..3c07e4a97 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -21,8 +21,10 @@ extern crate secp256k1; extern crate rand; +use clear_on_drop::ClearOnDrop; use self::rand::Rng; +use super::traits::asym::*; // reexports pub use self::secp256k1::{ @@ -52,18 +54,22 @@ pub fn minus_one_key() -> &'static SecretKey { &MINUS_ONE_KEY } +pub const SIGN_SIZE: usize = 65; -pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { +/// Warning we use 64 bit pubsize (first bytes of 65 bit representation is 4). +pub const PUB_SIZE: usize = 64; + +pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;SIGN_SIZE], Error> { let context = &SECP256K1; let sec = SecretKey::from_slice(context, &secret[..])?; let s = context.sign_recoverable(&Message::from_slice(message)?, &sec)?; let (rec_id, data) = s.serialize_compact(context); - let mut data_arr = [0; 65]; + let mut data_arr = [0; SIGN_SIZE]; // 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; + data_arr[0..PUB_SIZE].copy_from_slice(&data[0..PUB_SIZE]); + data_arr[PUB_SIZE] = rec_id.to_i32() as u8; Ok(data_arr) } @@ -71,12 +77,12 @@ pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { /// big doc about that!! pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; + let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; let sig = rsig.to_standard(context); - let pdata: [u8; 65] = { - let mut temp = [4u8; 65]; - temp[1..65].copy_from_slice(&*public); + let pdata: [u8; SIGN_SIZE] = { + let mut temp = [4u8; SIGN_SIZE]; + temp[1..SIGN_SIZE].copy_from_slice(&*public); temp }; @@ -88,31 +94,42 @@ pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result< } } -pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { +pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;PUB_SIZE], Error> { let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..64], RecoveryId::from_i32(signature[64] as i32)?)?; + let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; let serialized = pubkey.serialize_vec(context, false); - let mut res = [0;64]; - res.copy_from_slice(&serialized[1..65]); + let mut res = [0;PUB_SIZE]; + res.copy_from_slice(&serialized[1..PUB_SIZE + 1]); Ok(res) } +#[deprecated] +/// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. +/// The intent is to avoid depending on `Rng` trait. pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { SECP256K1.generate_keypair(r) .expect("context always created with full capabilities; qed") } +/// create a key pair from byte value of the secret key, the calling function is responsible for +/// erasing the input of memory. +pub fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(SecretKey, PublicKey), Error> { + assert!(sk_bytes.len() == SECRET_KEY_SIZE); + let sk = SecretKey::from_slice(&SECP256K1, sk_bytes)?; + let pk = PublicKey::from_secret_key(&SECP256K1, &sk)?; + Ok((sk, pk)) +} + // TODO change it to slicable u8 return type // Plus add comment explaining first bit removal -/// warning this returns 64 byte vec (we skip the first byte of 65 byte more standard +/// warning this returns PUB_SIZE byte vec (we skip the first byte of SIGN_SIZE byte more standard /// representation) pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { let mut a_vec = p.serialize_vec(&SECP256K1, false); - // &a_vec[1..65] - let _ = a_vec.drain(65..); + let _ = a_vec.drain(SIGN_SIZE..); a_vec.remove(0); a_vec } @@ -123,7 +140,7 @@ pub fn public_is_valid(p: &PublicKey) -> bool { /// only for test (or make the result erasable) pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { - p[..].to_vec() + ClearOnDrop::new(p[..].to_vec()) } pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { @@ -150,8 +167,8 @@ pub fn shared_secret(publ: &PublicKey, sec: &SecretKey) -> Result Result { let pdata = { - let mut temp = [4u8; 65]; - (&mut temp[1..65]).copy_from_slice(&public_sec_raw[0..64]); + let mut temp = [4u8; PUB_SIZE + 1]; + (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); temp }; @@ -188,7 +205,12 @@ pub fn secret_inv(mut sec_key: SecretKey) -> Result { } +struct Secp256k1; +impl AsymScheme for Secp256k1 { + type PublicKey = PublicKey; + type SecretKey = SecretKey; +} #[cfg(test)] mod tests { @@ -198,7 +220,7 @@ mod tests { secret_from_slice, verify_public, recover, - generate_keypair, + keypair_from_slice, public_to_vec, secret_to_vec, public_add, @@ -208,8 +230,10 @@ mod tests { secret_mul, secret_inv, one_key, + SECRET_KEY_SIZE, }; use self::rand::OsRng; + use self::rand::Rng; #[test] fn sign_val() { @@ -222,7 +246,9 @@ mod tests { #[test] fn sign_and_recover_public() { let mut osrng = OsRng::new().expect("test"); - let (secret, public) = generate_keypair(&mut osrng); + let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, public) = keypair_from_slice(&mut sec_buf).unwrap(); let message = vec![2;32]; let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); assert_eq!(&public_to_vec(&public).as_ref()[..], &recover(&signature, &message).unwrap()[..]); @@ -231,7 +257,9 @@ mod tests { #[test] fn sign_and_verify_public() { let mut osrng = OsRng::new().expect("test"); - let (secret, public) = generate_keypair(&mut osrng); + let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, public) = keypair_from_slice(&mut sec_buf).unwrap(); let message = vec![0;32]; let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); assert!(verify_public(&public_to_vec(&public).as_ref()[..], &signature, &message).unwrap()); @@ -263,8 +291,11 @@ mod tests { #[test] fn public_addition_is_commutative() { let mut osrng = OsRng::new().expect("test"); - let (_, public1) = generate_keypair(&mut osrng); - let (_, public2) = generate_keypair(&mut osrng); + let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public1) = keypair_from_slice(&mut sec_buf).unwrap(); + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public2) = keypair_from_slice(&mut sec_buf).unwrap(); let left = public_add(public1.clone(), &public2).unwrap(); @@ -276,8 +307,11 @@ mod tests { #[test] fn public_addition_is_reversible_with_subtraction() { let mut osrng = OsRng::new().expect("test"); - let (_, public1) = generate_keypair(&mut osrng); - let (_, public2) = generate_keypair(&mut osrng); + let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public1) = keypair_from_slice(&mut sec_buf).unwrap(); + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public2) = keypair_from_slice(&mut sec_buf).unwrap(); let sum = public_add(public1.clone(), &public2).unwrap(); let op = public_mul(public2.clone(), minus_one_key()).unwrap(); @@ -290,7 +324,10 @@ mod tests { #[test] fn multiplicating_secret_inversion_with_secret_gives_one() { let mut osrng = OsRng::new().expect("test"); - let (secret, _) = generate_keypair(&mut osrng); + let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, _) = keypair_from_slice(&mut sec_buf).unwrap(); + let inversion = secret_inv(secret.clone()).unwrap(); let inversion = secret_mul(inversion, &secret).unwrap(); assert_eq!(inversion, *one_key()); @@ -299,7 +336,9 @@ mod tests { #[test] fn secret_inversion_is_reversible_with_inversion() { let mut osrng = OsRng::new().expect("test"); - let (secret, _) = generate_keypair(&mut osrng); + let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, _) = keypair_from_slice(&mut sec_buf).unwrap(); let inversion = secret_inv(secret.clone()).unwrap(); let inversion = secret_inv(inversion).unwrap(); assert_eq!(inversion, secret); @@ -307,3 +346,5 @@ mod tests { } + + diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index e5ec8bd36..49f4d5187 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -20,7 +20,8 @@ extern crate libsecp256k1 as secp256k1; extern crate rand; use self::rand::Rng; - +use clear_on_drop::clear::Clear; +use clear_on_drop::ClearOnDrop; pub use self::secp256k1::{ Error, @@ -137,25 +138,41 @@ pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { Ok(res) } + +#[deprecated] /// random secret key for rand 0.5 pub fn random_sec(rng: &mut R) -> SecretKey { loop { let mut ret = [0u8; 32]; rng.fill_bytes(&mut ret); - match SecretKey::parse(&ret) { + match secret_from_slice(&ret) { Ok(key) => return key, Err(_) => (), } } } + +#[deprecated] +/// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. +/// The intent is to avoid depending on `Rng` trait. pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { let secret_key = random_sec(r); let public_key = PublicKey::from_secret_key(&secret_key); (secret_key, public_key) } +/// create a key pair from byte value of the secret key, the calling function is responsible for +/// erasing the input of memory. +pub fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(SecretKey, PublicKey), Error> { + assert!(sk_bytes.len() == SECRET_KEY_SIZE); + let secret_key = secret_from_slice(sk_bytes)?; + let public_key = PublicKey::from_secret_key(&secret_key); + Ok((secret_key, public_key)) +} + + /// warning this returns 64 byte vec (we skip the first byte of 65 byte more standard /// representation) pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { @@ -177,14 +194,19 @@ pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { /// only for test (or make the result erasable) pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { - p.serialize() + let mut b = p.serialize(); + let res = ClearOnDrop::new(b.to_vec()); + b.clear(); + res } /// 32 sized slice pub fn secret_from_slice(secret: &[u8]) -> Result { - let mut buf = [0;32]; + let mut buf = [0u8;32]; buf.copy_from_slice(&secret[..]); // panic on incorrect secret size - SecretKey::parse(&buf) + let res = SecretKey::parse(&buf)?; + buf.clear(); + Ok(res) } pub fn shared_secret(publ: &PublicKey, sec: &SecretKey) -> Result, Error> { @@ -215,6 +237,7 @@ fn aff_to_public(aff_pub: &mut Affine) -> Result { PublicKey::parse(&buff) } + pub fn public_add(pub_key: PublicKey, other_public: &PublicKey) -> Result { let mut aff_pub: Affine = pub_key.into(); let mut aff_pub_j = Jacobian::default(); From a976b473e3a4b2aad20f4b31b309f5374502ae8a Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 9 Nov 2018 20:22:14 +0100 Subject: [PATCH 22/39] Check point commit. --- parity-crypto/Cargo.toml | 1 + parity-crypto/src/error.rs | 20 +- parity-crypto/src/secp256k1.rs | 420 ++++++++++++++++++--------------- 3 files changed, 253 insertions(+), 188 deletions(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 44b72b7b5..96185b359 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -23,6 +23,7 @@ mem = { path = "../mem" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.13" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } +arrayvec = "0.4" # needed for eth-secp256k1 rand = "0.4" [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/parity-crypto/src/error.rs b/parity-crypto/src/error.rs index 42d42fa71..103875876 100644 --- a/parity-crypto/src/error.rs +++ b/parity-crypto/src/error.rs @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Parity. If not, see . +// along with Parity. If not, see . #[cfg(not(target_arch = "wasm32"))] use ring; @@ -20,8 +20,7 @@ use rscrypt; use block_modes; use raes; use aes_ctr; - - +use std::error::Error as StdError; quick_error! { #[derive(Debug)] @@ -34,9 +33,22 @@ quick_error! { cause(e) from() } + AsymShort(det: &'static str) { + description(det) + } + AsymFull(e: Box) { + cause(&**e) + description(e.description()) + } } } +impl Into for Error { + fn into(self) -> std::io::Error { + std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self)) + } +} + quick_error! { #[derive(Debug)] pub enum ScryptError { @@ -162,3 +174,5 @@ impl From for SymmError { SymmError(PrivSymmErr::KeyStream(e)) } } + + diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index 3c07e4a97..00597ff90 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -20,21 +20,26 @@ //! highly inefficient here. extern crate secp256k1; +extern crate arrayvec; extern crate rand; use clear_on_drop::ClearOnDrop; +use clear_on_drop::clear::Clear; +use self::arrayvec::ArrayVec; use self::rand::Rng; -use super::traits::asym::*; +use super::traits::asym::{SecretKey as SecretKeyTrait, PublicKey as PublicKeyTrait, Asym, FiniteField, FixAsymSharedSecret}; + +use super::error::Error; // reexports pub use self::secp256k1::{ - Error, + Error as InnerError, }; -pub use self::secp256k1::key::{SecretKey, PublicKey}; -pub use self::secp256k1::constants::{SECRET_KEY_SIZE, GENERATOR_X, GENERATOR_Y, CURVE_ORDER}; +pub use self::secp256k1::key::{SecretKey as SecretKeyInner, PublicKey}; +use self::secp256k1::constants::{SECRET_KEY_SIZE, GENERATOR_X, GENERATOR_Y, CURVE_ORDER}; -use self::secp256k1::key::{ONE_KEY, MINUS_ONE_KEY}; +use self::secp256k1::key::{ZERO_KEY as ZERO_BYTES, ONE_KEY as ONE_BYTES, MINUS_ONE_KEY as MINUS_ONE_BYTES}; use self::secp256k1::{ Message, RecoverableSignature, @@ -44,193 +49,240 @@ use self::secp256k1::{ lazy_static! { pub static ref SECP256K1: self::secp256k1::Secp256k1 = self::secp256k1::Secp256k1::new(); + static ref MINUS_ONE_KEY: SecretKey = SecretKey(MINUS_ONE_BYTES); + static ref ONE_KEY: SecretKey = SecretKey(ONE_BYTES); + static ref ZERO_KEY: SecretKey = SecretKey(ZERO_BYTES); } -pub fn one_key() -> &'static SecretKey { - &ONE_KEY +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SharedSecretAsRef(pub ecdh::SharedSecret); + +impl AsRef<[u8]> for SharedSecretAsRef { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } } -pub fn minus_one_key() -> &'static SecretKey { - &MINUS_ONE_KEY +const SIGN_SIZE: usize = 65; +const PUB_SIZE: usize = 64; + + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SecretKey(pub SecretKeyInner); + +impl Drop for SecretKey { + fn drop(&mut self) { + let len = self.0.len(); + unsafe { + let mut v = std::slice::from_raw_parts(self.0.as_mut_ptr(), len); + v.clear() + } + } } -pub const SIGN_SIZE: usize = 65; +impl Asym for Secp256k1 { + type PublicKey = PublicKey; + type SecretKey = SecretKey; + const SIGN_SIZE: usize = SIGN_SIZE; -/// Warning we use 64 bit pubsize (first bytes of 65 bit representation is 4). -pub const PUB_SIZE: usize = 64; + /// Warning we use 64 bit pubsize (first bytes of 65 bit representation is 4). + const PUB_SIZE: usize = PUB_SIZE; -pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;SIGN_SIZE], Error> { - let context = &SECP256K1; - let sec = SecretKey::from_slice(context, &secret[..])?; - let s = context.sign_recoverable(&Message::from_slice(message)?, &sec)?; - let (rec_id, data) = s.serialize_compact(context); - let mut data_arr = [0; SIGN_SIZE]; + const SECRET_SIZE: usize = SECRET_KEY_SIZE; - // no need to check if s is low, it always is - data_arr[0..PUB_SIZE].copy_from_slice(&data[0..PUB_SIZE]); - data_arr[PUB_SIZE] = rec_id.to_i32() as u8; - Ok(data_arr) -} + fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { + let context = &SECP256K1; + let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; + let sig = rsig.to_standard(context); -/// TODO use public as 65 instead ?? (here it is 64 but serialize as 65 usually) -> at least put a -/// big doc about that!! -pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { - let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; - let sig = rsig.to_standard(context); - - let pdata: [u8; SIGN_SIZE] = { - let mut temp = [4u8; SIGN_SIZE]; - temp[1..SIGN_SIZE].copy_from_slice(&*public); - temp - }; + let pdata: [u8; SIGN_SIZE] = { + let mut temp = [4u8; SIGN_SIZE]; + temp[1..SIGN_SIZE].copy_from_slice(&*public); + temp + }; - let publ = PublicKey::from_slice(context, &pdata)?; - match context.verify(&Message::from_slice(message)?, &sig, &publ) { - Ok(_) => Ok(true), - Err(Error::IncorrectSignature) => Ok(false), - Err(x) => Err(Error::from(x)) + let publ = PublicKey::from_slice(context, &pdata)?; + match context.verify(&Message::from_slice(message)?, &sig, &publ) { + Ok(_) => Ok(true), + Err(InnerError::IncorrectSignature) => Ok(false), + Err(x) => Err(InnerError::from(x).into()) + } } -} -pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;PUB_SIZE], Error> { - let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; - let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; - let serialized = pubkey.serialize_vec(context, false); + fn recover(signature: &[u8], message: &[u8]) -> Result, Error> { + let context = &SECP256K1; + let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; + let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; + let serialized = pubkey.serialize_vec(context, false); - let mut res = [0;PUB_SIZE]; - res.copy_from_slice(&serialized[1..PUB_SIZE + 1]); - Ok(res) -} + let mut res = vec![0;PUB_SIZE]; + res[..].copy_from_slice(&serialized[1..PUB_SIZE + 1]); + Ok(res) + } -#[deprecated] -/// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. -/// The intent is to avoid depending on `Rng` trait. -pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { - SECP256K1.generate_keypair(r) - .expect("context always created with full capabilities; qed") -} + /// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. + /// The intent is to avoid depending on `Rng` trait. + fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey) { + let (s, p) = SECP256K1.generate_keypair(r) + .expect("context always created with full capabilities; qed"); + (SecretKey(s), p) + } -/// create a key pair from byte value of the secret key, the calling function is responsible for -/// erasing the input of memory. -pub fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(SecretKey, PublicKey), Error> { - assert!(sk_bytes.len() == SECRET_KEY_SIZE); - let sk = SecretKey::from_slice(&SECP256K1, sk_bytes)?; - let pk = PublicKey::from_secret_key(&SECP256K1, &sk)?; - Ok((sk, pk)) -} + /// create a key pair from byte value of the secret key, the calling function is responsible for + /// erasing the input of memory. + fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error> { + assert!(sk_bytes.len() == SECRET_KEY_SIZE); + let sk = SecretKeyInner::from_slice(&SECP256K1, sk_bytes)?; + let pk = PublicKey::from_secret_key(&SECP256K1, &sk)?; + Ok((SecretKey(sk), pk)) + } -// TODO change it to slicable u8 return type -// Plus add comment explaining first bit removal -/// warning this returns PUB_SIZE byte vec (we skip the first byte of SIGN_SIZE byte more standard -/// representation) -pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { - let mut a_vec = p.serialize_vec(&SECP256K1, false); - let _ = a_vec.drain(SIGN_SIZE..); - a_vec.remove(0); - a_vec -} + fn public_from_secret(s: &Self::SecretKey) -> Result { + Ok(PublicKey::from_secret_key(&SECP256K1, &s.0)?) + } -pub fn public_is_valid(p: &PublicKey) -> bool { - p.is_valid() -} + /// using a shortened 64bit public key as input + fn public_from_slice(public_sec_raw: &[u8]) -> Result { + let pdata = { + let mut temp = [4u8; PUB_SIZE + 1]; + (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); + temp + }; + Ok(PublicKey::from_slice(&SECP256K1, &pdata)?) + } + + fn secret_from_slice(secret: &[u8]) -> Result { + Ok(SecretKey(SecretKeyInner::from_slice(&SECP256K1, secret)?)) + } -/// only for test (or make the result erasable) -pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { - ClearOnDrop::new(p[..].to_vec()) -} -pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { - p.serialize_vec(&SECP256K1, true) -} -pub fn secret_from_slice(secret: &[u8]) -> Result { - SecretKey::from_slice(&SECP256K1, secret) } -pub struct SharedSecretAsRef(pub ecdh::SharedSecret); +impl FixAsymSharedSecret for SecretKey { + type Other = PublicKey; + type Result = SharedSecretAsRef; -impl AsRef<[u8]> for SharedSecretAsRef { - fn as_ref(&self) -> &[u8] { - &self.0[..] + fn shared_secret(&self, publ: &Self::Other) -> Result { + let shared = ecdh::SharedSecret::new_raw(&SECP256K1, &publ, &self.0); + Ok(SharedSecretAsRef(shared)) } -} -pub fn shared_secret(publ: &PublicKey, sec: &SecretKey) -> Result, Error> { - let shared = ecdh::SharedSecret::new_raw(&SECP256K1, &publ, &sec); - Ok(SharedSecretAsRef(shared)) } - -/// using a shortened 64bit public key as input -pub fn public_from_slice(public_sec_raw: &[u8]) -> Result { - let pdata = { - let mut temp = [4u8; PUB_SIZE + 1]; - (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); - temp - }; - PublicKey::from_slice(&SECP256K1, &pdata) -} +impl SecretKeyTrait for SecretKey { + type VecRepr = ClearOnDrop>; -pub fn public_from_secret(s: &SecretKey) -> Result { - PublicKey::from_secret_key(&SECP256K1, &s) -} + fn sign(&self, message: &[u8]) -> Result, Error> { + let context = &SECP256K1; + let s = context.sign_recoverable(&Message::from_slice(message)?, &self.0)?; + let (rec_id, data) = s.serialize_compact(context); + let mut data_arr = vec![0; SIGN_SIZE]; -pub fn public_mul(mut pub_key: PublicKey, sec_key: &SecretKey) -> Result { - pub_key.mul_assign(&SECP256K1, sec_key)?; - Ok(pub_key) -} + // no need to check if s is low, it always is + data_arr[0..PUB_SIZE].copy_from_slice(&data[0..PUB_SIZE]); + data_arr[PUB_SIZE] = rec_id.to_i32() as u8; + Ok(data_arr) + } -pub fn public_add(mut pub_key: PublicKey, other_public: &PublicKey) -> Result { - pub_key.add_assign(&SECP256K1, other_public)?; - Ok(pub_key) -} + fn to_vec(&self) -> Self::VecRepr { + ClearOnDrop::new(self.0[..].to_vec()) + } -pub fn secret_mul(mut sec_key: SecretKey, other_secret: &SecretKey) -> Result { - sec_key.mul_assign(&SECP256K1, other_secret)?; - Ok(sec_key) } -pub fn secret_add(mut sec_key: SecretKey, other_secret: &SecretKey) -> Result { - sec_key.add_assign(&SECP256K1, other_secret)?; - Ok(sec_key) -} +impl PublicKeyTrait for PublicKey { + type VecRepr = ArrayVec<[u8; 72]>; + + /// warning this returns PUB_SIZE byte vec (we skip the first byte of SIGN_SIZE byte more standard + /// representation) + fn to_vec(&self) -> Self::VecRepr { + let mut a_vec = self.serialize_vec(&SECP256K1, false); + let _ = a_vec.drain(SIGN_SIZE..); + a_vec.remove(0); + a_vec + } + + /// Should move to another trait. + fn to_compressed_vec(p: &Self) -> Self::VecRepr { + p.serialize_vec(&SECP256K1, true) + } + + fn is_valid(&self) -> bool { + self.is_valid() + } -pub fn secret_inv(mut sec_key: SecretKey) -> Result { - sec_key.inv_assign(&SECP256K1)?; - Ok(sec_key) } +pub struct Secp256k1; + +impl FiniteField for Secp256k1 { + + fn generator_x() -> &'static[u8] { &GENERATOR_X[..] } + fn generator_y() -> &'static[u8] { &GENERATOR_Y[..] } + fn curve_order() -> &'static[u8] { &CURVE_ORDER[..] } + + fn public_mul(mut pub_key: Self::PublicKey, sec_key: &Self::SecretKey) -> Result { + pub_key.mul_assign(&SECP256K1, &sec_key.0)?; + Ok(pub_key) + } + + fn public_add(mut pub_key: Self::PublicKey, other_public: &Self::PublicKey) -> Result { + pub_key.add_assign(&SECP256K1, other_public)?; + Ok(pub_key) + } + + fn secret_mul(mut sec_key: Self::SecretKey, other_secret: &Self::SecretKey) -> Result { + sec_key.0.mul_assign(&SECP256K1, &other_secret.0)?; + Ok(sec_key) + } -struct Secp256k1; + fn secret_add(mut sec_key: Self::SecretKey, other_secret: &Self::SecretKey) -> Result { + sec_key.0.add_assign(&SECP256K1, &other_secret.0)?; + Ok(sec_key) + } + + fn secret_inv(mut sec_key: Self::SecretKey) -> Result { + sec_key.0.inv_assign(&SECP256K1)?; + Ok(sec_key) + } + + fn one_key() -> &'static Self::SecretKey { + &ONE_KEY + } + + fn zero_key() -> &'static Self::SecretKey { + &ZERO_KEY + } -impl AsymScheme for Secp256k1 { - type PublicKey = PublicKey; - type SecretKey = SecretKey; + fn minus_one_key() -> &'static Self::SecretKey { + &MINUS_ONE_KEY + } + +} + +impl From for Error { + fn from(err: InnerError) -> Self { + match err { + InnerError::InvalidSecretKey => Error::AsymShort("Invalid secret"), + InnerError::InvalidRecoveryId => Error::AsymShort("Invalid recovery id"), + InnerError::InvalidPublicKey => Error::AsymShort("Invalid public"), + InnerError::InvalidSignature | + InnerError::IncorrectSignature => Error::AsymShort("Invalid EC signature"), + InnerError::InvalidMessage => Error::AsymShort("Invalid AES message"), + _ => Error::AsymFull(Box::new(err)) + } + } } #[cfg(test)] mod tests { extern crate rand; + use ::traits::asym::*; use super::{ - sign, - secret_from_slice, - verify_public, - recover, - keypair_from_slice, - public_to_vec, - secret_to_vec, - public_add, - public_from_slice, - public_mul, - minus_one_key, - secret_mul, - secret_inv, - one_key, - SECRET_KEY_SIZE, + Secp256k1, }; use self::rand::OsRng; use self::rand::Rng; @@ -238,68 +290,69 @@ mod tests { #[test] fn sign_val() { let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let sec = Secp256k1::secret_from_slice(&sk).unwrap(); let message = vec![2;32]; - let signature = sign(&sk[..], &message).unwrap(); + let signature = sec.sign(&message).unwrap(); assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); } #[test] fn sign_and_recover_public() { let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); - let (secret, public) = keypair_from_slice(&mut sec_buf).unwrap(); + let (secret, public) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); let message = vec![2;32]; - let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); - assert_eq!(&public_to_vec(&public).as_ref()[..], &recover(&signature, &message).unwrap()[..]); + let signature = secret.sign(&message).unwrap(); + assert_eq!(&public.to_vec().as_ref()[..], &Secp256k1::recover(&signature, &message).unwrap()[..]); } #[test] fn sign_and_verify_public() { let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); - let (secret, public) = keypair_from_slice(&mut sec_buf).unwrap(); + let (secret, public) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); let message = vec![0;32]; - let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); - assert!(verify_public(&public_to_vec(&public).as_ref()[..], &signature, &message).unwrap()); + let signature = secret.sign(&message).unwrap(); + assert!(Secp256k1::verify_public(&public.to_vec().as_ref()[..], &signature, &message).unwrap()); } #[test] fn public_addition() { let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; - let pub1 = public_from_slice(&pk1[..]).unwrap(); - let pub2 = public_from_slice(&pk2[..]).unwrap(); - let res = public_add(pub1, &pub2).unwrap(); + let pub1 = Secp256k1::public_from_slice(&pk1[..]).unwrap(); + let pub2 = Secp256k1::public_from_slice(&pk2[..]).unwrap(); + let res = Secp256k1::public_add(pub1, &pub2).unwrap(); - assert_eq!(&public_to_vec(&res).as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + assert_eq!(&res.to_vec().as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); } #[test] fn public_multiplication() { let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let pubk = public_from_slice(&pk[..]).unwrap(); - let sec = secret_from_slice(&sk[..]).unwrap(); - let res = public_mul(pubk, &sec).unwrap(); + let pubk = Secp256k1::public_from_slice(&pk[..]).unwrap(); + let sec = Secp256k1::secret_from_slice(&sk[..]).unwrap(); + let res = Secp256k1::public_mul(pubk, &sec).unwrap(); - assert_eq!(&public_to_vec(&res).as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + assert_eq!(&res.to_vec().as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); } #[test] fn public_addition_is_commutative() { let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); - let (_, public1) = keypair_from_slice(&mut sec_buf).unwrap(); + let (_, public1) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); osrng.fill_bytes(&mut sec_buf[..]); - let (_, public2) = keypair_from_slice(&mut sec_buf).unwrap(); + let (_, public2) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let left = public_add(public1.clone(), &public2).unwrap(); + let left = Secp256k1::public_add(public1.clone(), &public2).unwrap(); - let right = public_add(public2.clone(), &public1).unwrap(); + let right = Secp256k1::public_add(public2.clone(), &public1).unwrap(); assert_eq!(left, right); } @@ -307,15 +360,15 @@ mod tests { #[test] fn public_addition_is_reversible_with_subtraction() { let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); - let (_, public1) = keypair_from_slice(&mut sec_buf).unwrap(); + let (_, public1) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); osrng.fill_bytes(&mut sec_buf[..]); - let (_, public2) = keypair_from_slice(&mut sec_buf).unwrap(); + let (_, public2) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let sum = public_add(public1.clone(), &public2).unwrap(); - let op = public_mul(public2.clone(), minus_one_key()).unwrap(); - let sum = public_add(sum, &op).unwrap(); + let sum = Secp256k1::public_add(public1.clone(), &public2).unwrap(); + let op = Secp256k1::public_mul(public2.clone(), Secp256k1::minus_one_key()).unwrap(); + let sum = Secp256k1::public_add(sum, &op).unwrap(); assert_eq!(sum, public1); } @@ -324,27 +377,24 @@ mod tests { #[test] fn multiplicating_secret_inversion_with_secret_gives_one() { let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); - let (secret, _) = keypair_from_slice(&mut sec_buf).unwrap(); + let (secret, _) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let inversion = secret_inv(secret.clone()).unwrap(); - let inversion = secret_mul(inversion, &secret).unwrap(); - assert_eq!(inversion, *one_key()); + let inversion = Secp256k1::secret_inv(secret.clone()).unwrap(); + let inversion = Secp256k1::secret_mul(inversion, &secret).unwrap(); + assert_eq!(inversion, *Secp256k1::one_key()); } #[test] fn secret_inversion_is_reversible_with_inversion() { let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; SECRET_KEY_SIZE]; + let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); - let (secret, _) = keypair_from_slice(&mut sec_buf).unwrap(); - let inversion = secret_inv(secret.clone()).unwrap(); - let inversion = secret_inv(inversion).unwrap(); + let (secret, _) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); + let inversion = Secp256k1::secret_inv(secret.clone()).unwrap(); + let inversion = Secp256k1::secret_inv(inversion).unwrap(); assert_eq!(inversion, secret); } } - - - From e41feabccda414d8467228cd50ec808b4d6a2aa2 Mon Sep 17 00:00:00 2001 From: cheme Date: Sat, 10 Nov 2018 09:48:19 +0100 Subject: [PATCH 23/39] Switching to more aligned to parity-eth code base refacto (make key `AsRef`). --- parity-crypto/src/secp256k1.rs | 146 +++++++++++++++++------------ parity-crypto/src/secp256k1_alt.rs | 23 +++++ 2 files changed, 109 insertions(+), 60 deletions(-) diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index 00597ff90..b8746ab26 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -22,7 +22,6 @@ extern crate secp256k1; extern crate arrayvec; extern crate rand; -use clear_on_drop::ClearOnDrop; use clear_on_drop::clear::Clear; use self::arrayvec::ArrayVec; @@ -36,7 +35,7 @@ pub use self::secp256k1::{ Error as InnerError, }; -pub use self::secp256k1::key::{SecretKey as SecretKeyInner, PublicKey}; +pub use self::secp256k1::key::{SecretKey as SecretKeyInner, PublicKey as PublicKeyInner}; use self::secp256k1::constants::{SECRET_KEY_SIZE, GENERATOR_X, GENERATOR_Y, CURVE_ORDER}; use self::secp256k1::key::{ZERO_KEY as ZERO_BYTES, ONE_KEY as ONE_BYTES, MINUS_ONE_KEY as MINUS_ONE_BYTES}; @@ -66,18 +65,35 @@ impl AsRef<[u8]> for SharedSecretAsRef { const SIGN_SIZE: usize = 65; const PUB_SIZE: usize = 64; +// not vec size could be reduce to 64 (higher instantiation cost) +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct PublicKey(PublicKeyInner, ArrayVec<[u8;72]>); + +impl PublicKey { + + fn new(inner: PublicKeyInner) -> Self { + let a_vec = inner.serialize_vec(&SECP256K1, false); + PublicKey(inner, a_vec) + } + + fn refresh(&mut self) { + let a_vec = self.0.serialize_vec(&SECP256K1, false); + self.1 = a_vec; + } + +} #[derive(PartialEq, Eq, Debug, Clone)] pub struct SecretKey(pub SecretKeyInner); impl Drop for SecretKey { - fn drop(&mut self) { - let len = self.0.len(); - unsafe { - let mut v = std::slice::from_raw_parts(self.0.as_mut_ptr(), len); - v.clear() - } - } + fn drop(&mut self) { + let len = self.0.len(); + unsafe { + let mut v = std::slice::from_raw_parts(self.0.as_mut_ptr(), len); + v.clear() + } + } } impl Asym for Secp256k1 { @@ -91,34 +107,16 @@ impl Asym for Secp256k1 { const SECRET_SIZE: usize = SECRET_KEY_SIZE; - fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { - let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; - let sig = rsig.to_standard(context); - - let pdata: [u8; SIGN_SIZE] = { - let mut temp = [4u8; SIGN_SIZE]; - temp[1..SIGN_SIZE].copy_from_slice(&*public); - temp - }; - - let publ = PublicKey::from_slice(context, &pdata)?; - match context.verify(&Message::from_slice(message)?, &sig, &publ) { - Ok(_) => Ok(true), - Err(InnerError::IncorrectSignature) => Ok(false), - Err(x) => Err(InnerError::from(x).into()) - } - } - - fn recover(signature: &[u8], message: &[u8]) -> Result, Error> { + fn recover(signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; - let serialized = pubkey.serialize_vec(context, false); + Ok(PublicKey::new(pubkey)) + //let serialized = pubkey.serialize_vec(context, false); - let mut res = vec![0;PUB_SIZE]; - res[..].copy_from_slice(&serialized[1..PUB_SIZE + 1]); - Ok(res) + //let mut res = vec![0;PUB_SIZE]; + //res[..].copy_from_slice(&serialized[1..PUB_SIZE + 1]); + //Ok(res) } @@ -127,7 +125,7 @@ impl Asym for Secp256k1 { fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey) { let (s, p) = SECP256K1.generate_keypair(r) .expect("context always created with full capabilities; qed"); - (SecretKey(s), p) + (SecretKey(s), PublicKey::new(p)) } /// create a key pair from byte value of the secret key, the calling function is responsible for @@ -135,12 +133,13 @@ impl Asym for Secp256k1 { fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error> { assert!(sk_bytes.len() == SECRET_KEY_SIZE); let sk = SecretKeyInner::from_slice(&SECP256K1, sk_bytes)?; - let pk = PublicKey::from_secret_key(&SECP256K1, &sk)?; - Ok((SecretKey(sk), pk)) + let sc = SecretKey(sk); + let pk = PublicKeyInner::from_secret_key(&SECP256K1, &sc.0)?; + Ok((sc, PublicKey::new(pk))) } fn public_from_secret(s: &Self::SecretKey) -> Result { - Ok(PublicKey::from_secret_key(&SECP256K1, &s.0)?) + Ok(PublicKey::new(PublicKeyInner::from_secret_key(&SECP256K1, &s.0)?)) } /// using a shortened 64bit public key as input @@ -150,7 +149,7 @@ impl Asym for Secp256k1 { (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); temp }; - Ok(PublicKey::from_slice(&SECP256K1, &pdata)?) + Ok(PublicKey::new(PublicKeyInner::from_slice(&SECP256K1, &pdata)?)) } fn secret_from_slice(secret: &[u8]) -> Result { @@ -166,14 +165,14 @@ impl FixAsymSharedSecret for SecretKey { type Result = SharedSecretAsRef; fn shared_secret(&self, publ: &Self::Other) -> Result { - let shared = ecdh::SharedSecret::new_raw(&SECP256K1, &publ, &self.0); + let shared = ecdh::SharedSecret::new_raw(&SECP256K1, &publ.0, &self.0); Ok(SharedSecretAsRef(shared)) } } impl SecretKeyTrait for SecretKey { - type VecRepr = ClearOnDrop>; + //type VecRepr = ClearOnDrop>; fn sign(&self, message: &[u8]) -> Result, Error> { let context = &SECP256K1; @@ -187,35 +186,60 @@ impl SecretKeyTrait for SecretKey { Ok(data_arr) } - fn to_vec(&self) -> Self::VecRepr { + /*fn to_vec(&self) -> Self::VecRepr { ClearOnDrop::new(self.0[..].to_vec()) - } + }*/ + +} +impl AsRef<[u8]> for SecretKey { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } } impl PublicKeyTrait for PublicKey { type VecRepr = ArrayVec<[u8; 72]>; - /// warning this returns PUB_SIZE byte vec (we skip the first byte of SIGN_SIZE byte more standard - /// representation) - fn to_vec(&self) -> Self::VecRepr { + /*fn to_vec(&self) -> Self::VecRepr { let mut a_vec = self.serialize_vec(&SECP256K1, false); - let _ = a_vec.drain(SIGN_SIZE..); + let _ = a_vec.drain(PUB_SIZE + 1..); a_vec.remove(0); a_vec - } + }*/ /// Should move to another trait. fn to_compressed_vec(p: &Self) -> Self::VecRepr { - p.serialize_vec(&SECP256K1, true) + p.0.serialize_vec(&SECP256K1, true) } fn is_valid(&self) -> bool { - self.is_valid() + self.0.is_valid() + } + + fn verify(&self, signature: &[u8], message: &[u8]) -> Result { + let context = &SECP256K1; + let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; + let sig = rsig.to_standard(context); + + match context.verify(&Message::from_slice(message)?, &sig, &self.0) { + Ok(_) => Ok(true), + Err(InnerError::IncorrectSignature) => Ok(false), + Err(x) => Err(InnerError::from(x).into()) + } } } +// warning it returns PUB_SIZE byte vec (we skip the first byte of SIGN_SIZE byte more standard +// representation) +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + &self.1[1 .. 1 + PUB_SIZE] + } +} + + pub struct Secp256k1; impl FiniteField for Secp256k1 { @@ -225,12 +249,14 @@ impl FiniteField for Secp256k1 { fn curve_order() -> &'static[u8] { &CURVE_ORDER[..] } fn public_mul(mut pub_key: Self::PublicKey, sec_key: &Self::SecretKey) -> Result { - pub_key.mul_assign(&SECP256K1, &sec_key.0)?; + pub_key.0.mul_assign(&SECP256K1, &sec_key.0)?; + pub_key.refresh(); Ok(pub_key) } fn public_add(mut pub_key: Self::PublicKey, other_public: &Self::PublicKey) -> Result { - pub_key.add_assign(&SECP256K1, other_public)?; + pub_key.0.add_assign(&SECP256K1, &other_public.0)?; + pub_key.refresh(); Ok(pub_key) } @@ -265,15 +291,15 @@ impl FiniteField for Secp256k1 { impl From for Error { fn from(err: InnerError) -> Self { - match err { + match err { InnerError::InvalidSecretKey => Error::AsymShort("Invalid secret"), InnerError::InvalidRecoveryId => Error::AsymShort("Invalid recovery id"), InnerError::InvalidPublicKey => Error::AsymShort("Invalid public"), InnerError::InvalidSignature | - InnerError::IncorrectSignature => Error::AsymShort("Invalid EC signature"), + InnerError::IncorrectSignature => Error::AsymShort("Invalid EC signature"), InnerError::InvalidMessage => Error::AsymShort("Invalid AES message"), - _ => Error::AsymFull(Box::new(err)) - } + _ => Error::AsymFull(Box::new(err)) + } } } @@ -290,7 +316,7 @@ mod tests { #[test] fn sign_val() { let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let sec = Secp256k1::secret_from_slice(&sk).unwrap(); + let sec = Secp256k1::secret_from_slice(&sk).unwrap(); let message = vec![2;32]; let signature = sec.sign(&message).unwrap(); assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); @@ -304,7 +330,7 @@ mod tests { let (secret, public) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); let message = vec![2;32]; let signature = secret.sign(&message).unwrap(); - assert_eq!(&public.to_vec().as_ref()[..], &Secp256k1::recover(&signature, &message).unwrap()[..]); + assert_eq!(public, Secp256k1::recover(&signature, &message).unwrap()); } #[test] @@ -315,7 +341,7 @@ mod tests { let (secret, public) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); let message = vec![0;32]; let signature = secret.sign(&message).unwrap(); - assert!(Secp256k1::verify_public(&public.to_vec().as_ref()[..], &signature, &message).unwrap()); + assert!(public.verify(&signature, &message).unwrap()); } #[test] @@ -326,7 +352,7 @@ mod tests { let pub2 = Secp256k1::public_from_slice(&pk2[..]).unwrap(); let res = Secp256k1::public_add(pub1, &pub2).unwrap(); - assert_eq!(&res.to_vec().as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + assert_eq!(&res.as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); } #[test] @@ -337,7 +363,7 @@ mod tests { let sec = Secp256k1::secret_from_slice(&sk[..]).unwrap(); let res = Secp256k1::public_mul(pubk, &sec).unwrap(); - assert_eq!(&res.to_vec().as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + assert_eq!(&res.as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); } diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 49f4d5187..0970de21f 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -22,6 +22,7 @@ extern crate rand; use self::rand::Rng; use clear_on_drop::clear::Clear; use clear_on_drop::ClearOnDrop; +use ::traits::asym::{PublicKey as PublicKeyTrait}; pub use self::secp256k1::{ Error, @@ -308,7 +309,29 @@ pub fn secret_inv(sec_key: SecretKey) -> Result { SecretKey::parse(&res.0.b32()) } +/* +impl PublicKeyTrait for PublicKey { + type VecRepr = Vec; + fn to_vec(&self) -> Self::VecRepr { + unimplemented!() + } + + /// Should move to another trait. + fn to_compressed_vec(p: &Self) -> Self::VecRepr { + unimplemented!() + } + + fn is_valid(&self) -> bool { + unimplemented!() + } + + fn verify(&self, signature: &[u8], message: &[u8]) -> Result { + unimplemented!() + } + +} +*/ From a24dbd0bbba146de7b7ed9761bcde8f0be69be71 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 13 Nov 2018 20:15:37 +0100 Subject: [PATCH 24/39] Switch arithmetic trait to simple mut ref (better for using with type struct). --- parity-crypto/src/secp256k1.rs | 70 +++++++++++++++++++----------- parity-crypto/src/secp256k1_alt.rs | 30 ++++++++----- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index b8746ab26..f32ec541d 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -51,6 +51,7 @@ lazy_static! { static ref MINUS_ONE_KEY: SecretKey = SecretKey(MINUS_ONE_BYTES); static ref ONE_KEY: SecretKey = SecretKey(ONE_BYTES); static ref ZERO_KEY: SecretKey = SecretKey(ZERO_BYTES); + static ref NULL_PUB_K: PublicKey = PublicKey::unsafe_empty(); } #[derive(PartialEq, Eq, Debug, Clone)] @@ -81,6 +82,9 @@ impl PublicKey { self.1 = a_vec; } + fn unsafe_empty() -> Self { + PublicKey(PublicKeyInner::new(), [0;72].into()) + } } #[derive(PartialEq, Eq, Debug, Clone)] @@ -248,31 +252,31 @@ impl FiniteField for Secp256k1 { fn generator_y() -> &'static[u8] { &GENERATOR_Y[..] } fn curve_order() -> &'static[u8] { &CURVE_ORDER[..] } - fn public_mul(mut pub_key: Self::PublicKey, sec_key: &Self::SecretKey) -> Result { + fn public_mul(pub_key: &mut Self::PublicKey, sec_key: &Self::SecretKey) -> Result<(), Error> { pub_key.0.mul_assign(&SECP256K1, &sec_key.0)?; pub_key.refresh(); - Ok(pub_key) + Ok(()) } - fn public_add(mut pub_key: Self::PublicKey, other_public: &Self::PublicKey) -> Result { + fn public_add(pub_key: &mut Self::PublicKey, other_public: &Self::PublicKey) -> Result<(), Error> { pub_key.0.add_assign(&SECP256K1, &other_public.0)?; pub_key.refresh(); - Ok(pub_key) + Ok(()) } - fn secret_mul(mut sec_key: Self::SecretKey, other_secret: &Self::SecretKey) -> Result { + fn secret_mul(sec_key: &mut Self::SecretKey, other_secret: &Self::SecretKey) -> Result<(), Error> { sec_key.0.mul_assign(&SECP256K1, &other_secret.0)?; - Ok(sec_key) + Ok(()) } - fn secret_add(mut sec_key: Self::SecretKey, other_secret: &Self::SecretKey) -> Result { + fn secret_add(sec_key: &mut Self::SecretKey, other_secret: &Self::SecretKey) -> Result<(), Error> { sec_key.0.add_assign(&SECP256K1, &other_secret.0)?; - Ok(sec_key) + Ok(()) } - fn secret_inv(mut sec_key: Self::SecretKey) -> Result { + fn secret_inv(sec_key: &mut Self::SecretKey) -> Result<(), Error> { sec_key.0.inv_assign(&SECP256K1)?; - Ok(sec_key) + Ok(()) } fn one_key() -> &'static Self::SecretKey { @@ -348,22 +352,22 @@ mod tests { fn public_addition() { let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; - let pub1 = Secp256k1::public_from_slice(&pk1[..]).unwrap(); + let mut pub1 = Secp256k1::public_from_slice(&pk1[..]).unwrap(); let pub2 = Secp256k1::public_from_slice(&pk2[..]).unwrap(); - let res = Secp256k1::public_add(pub1, &pub2).unwrap(); + Secp256k1::public_add(&mut pub1, &pub2).unwrap(); - assert_eq!(&res.as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + assert_eq!(&pub1.as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); } #[test] fn public_multiplication() { let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let pubk = Secp256k1::public_from_slice(&pk[..]).unwrap(); + let mut pubk = Secp256k1::public_from_slice(&pk[..]).unwrap(); let sec = Secp256k1::secret_from_slice(&sk[..]).unwrap(); - let res = Secp256k1::public_mul(pubk, &sec).unwrap(); + Secp256k1::public_mul(&mut pubk, &sec).unwrap(); - assert_eq!(&res.as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + assert_eq!(&pubk.as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); } @@ -376,9 +380,11 @@ mod tests { osrng.fill_bytes(&mut sec_buf[..]); let (_, public2) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let left = Secp256k1::public_add(public1.clone(), &public2).unwrap(); + let mut left = public1.clone(); + Secp256k1::public_add(&mut left, &public2).unwrap(); - let right = Secp256k1::public_add(public2.clone(), &public1).unwrap(); + let mut right = public2.clone(); + Secp256k1::public_add(&mut right, &public1).unwrap(); assert_eq!(left, right); } @@ -392,9 +398,11 @@ mod tests { osrng.fill_bytes(&mut sec_buf[..]); let (_, public2) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let sum = Secp256k1::public_add(public1.clone(), &public2).unwrap(); - let op = Secp256k1::public_mul(public2.clone(), Secp256k1::minus_one_key()).unwrap(); - let sum = Secp256k1::public_add(sum, &op).unwrap(); + let mut sum = public1.clone(); + Secp256k1::public_add(&mut sum, &public2).unwrap(); + let mut op = public2.clone(); + Secp256k1::public_mul(&mut op, Secp256k1::minus_one_key()).unwrap(); + Secp256k1::public_add(&mut sum, &op).unwrap(); assert_eq!(sum, public1); } @@ -407,8 +415,9 @@ mod tests { osrng.fill_bytes(&mut sec_buf[..]); let (secret, _) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let inversion = Secp256k1::secret_inv(secret.clone()).unwrap(); - let inversion = Secp256k1::secret_mul(inversion, &secret).unwrap(); + let mut inversion = secret.clone(); + Secp256k1::secret_inv(&mut inversion).unwrap(); + Secp256k1::secret_mul(&mut inversion, &secret).unwrap(); assert_eq!(inversion, *Secp256k1::one_key()); } @@ -418,9 +427,20 @@ mod tests { let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; osrng.fill_bytes(&mut sec_buf[..]); let (secret, _) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let inversion = Secp256k1::secret_inv(secret.clone()).unwrap(); - let inversion = Secp256k1::secret_inv(inversion).unwrap(); + let mut inversion = secret.clone(); + Secp256k1::secret_inv(&mut inversion).unwrap(); + Secp256k1::secret_inv(&mut inversion).unwrap(); assert_eq!(inversion, secret); } } + +/// Default implementation is only for parity-ethereum secret-store +/// It would be good to remove it (there is a bit of refactoring). +/// Therefore the constraint is not explicit. +/// Please note that it is an invalid publickey. +impl Default for PublicKey { + fn default() -> Self { + NULL_PUB_K.clone() + } +} diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 0970de21f..7d22ffe9a 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -195,10 +195,10 @@ pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { /// only for test (or make the result erasable) pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { - let mut b = p.serialize(); + let mut b = p.serialize(); let res = ClearOnDrop::new(b.to_vec()); - b.clear(); - res + b.clear(); + res } /// 32 sized slice @@ -314,25 +314,31 @@ impl PublicKeyTrait for PublicKey { type VecRepr = Vec; fn to_vec(&self) -> Self::VecRepr { - unimplemented!() - } + unimplemented!() + } /// Should move to another trait. fn to_compressed_vec(p: &Self) -> Self::VecRepr { - unimplemented!() - } + unimplemented!() + } fn is_valid(&self) -> bool { - unimplemented!() - } + unimplemented!() + } - fn verify(&self, signature: &[u8], message: &[u8]) -> Result { - unimplemented!() - } + fn verify(&self, signature: &[u8], message: &[u8]) -> Result { + unimplemented!() + } } */ +//#[test] failing test will make it difficulte to use secret-store +fn zeroed_pk() { + let mut val = [0;65]; + val[0] = 4; + assert!(PublicKey::parse(&val).is_ok()); +} #[cfg(test)] From 944570254a48cf6e5c4c6a1b6e2a7dccc9eabb6b Mon Sep 17 00:00:00 2001 From: cheme Date: Wed, 14 Nov 2018 17:31:31 +0100 Subject: [PATCH 25/39] Test async trait and bench it too. Impl alt secp as asym trait. Add missing files from previous commits. --- parity-crypto/Cargo.toml | 18 +- parity-crypto/benches/asym.rs | 60 +++ parity-crypto/benches/bench.rs | 62 +++ parity-crypto/libsecp256k1/Cargo.toml | 10 + parity-crypto/libsecp256k1/src/lib.rs | 23 ++ parity-crypto/src/aes.rs | 10 +- parity-crypto/src/error.rs | 36 +- parity-crypto/src/hmac.rs | 70 ++-- parity-crypto/src/hmac_alt.rs | 35 +- parity-crypto/src/lib.rs | 8 +- parity-crypto/src/pbkdf2.rs | 31 +- parity-crypto/src/pbkdf2_alt.rs | 13 +- parity-crypto/src/secp256k1.rs | 140 +------ parity-crypto/src/secp256k1_alt.rs | 572 +++++++++++++------------- parity-crypto/src/traits/asym.rs | 277 +++++++++++++ parity-crypto/src/traits/mod.rs | 26 ++ 16 files changed, 857 insertions(+), 534 deletions(-) create mode 100644 parity-crypto/benches/asym.rs create mode 100644 parity-crypto/benches/bench.rs create mode 100644 parity-crypto/libsecp256k1/Cargo.toml create mode 100644 parity-crypto/libsecp256k1/src/lib.rs create mode 100644 parity-crypto/src/traits/asym.rs create mode 100644 parity-crypto/src/traits/mod.rs diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 96185b359..e1066d496 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -5,6 +5,12 @@ authors = ["Parity Technologies "] repository = "https://github.com/paritytech/parity-common" description = "Crypto utils used by ethstore and network." license = "GPL-3.0" +autobenches = false + +[[bench]] +name = "bench" +harness = false + [dependencies] quick-error = "1.2.2" @@ -14,9 +20,9 @@ scrypt = { version = "0.1.1", default-features = false } ripemd160 = "0.8.0" sha2 = "0.8.0" digest = "0.8" -aes = "0.2.0" -aes-ctr = "0.1.0" -block-modes = "0.1.0" +aes = "0.3.2" +aes-ctr = "0.3.0" +block-modes = "0.2.0" lazy_static = "1.0" # for secp mem = { path = "../mem" } @@ -25,6 +31,9 @@ ring = "0.13" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } arrayvec = "0.4" # needed for eth-secp256k1 rand = "0.4" +hmac = { version = "0.7", optional = true } +libsecp256k1 = { path = "./libsecp256k1", optional = true } +pbkdf2 = { version = "0.3", default-features = false, optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] hmac = "0.7" @@ -39,7 +48,10 @@ hmac = "0.7" # libsecp256k1 = { version = "0.1", package = "libsecp256k1" } // requires 'rename-dependency' in stable libsecp256k1 = { path = "./libsecp256k1" } pbkdf2 = { version = "0.3", default-features = false } +criterion = "0.2" [features] +# expose alternative wasm32 implementation for testing and benchmarks +alt = ["hmac", "libsecp256k1", "pbkdf2"] nightly = ["subtle/nightly"] volatile-erase = ["mem/volatile-erase"] diff --git a/parity-crypto/benches/asym.rs b/parity-crypto/benches/asym.rs new file mode 100644 index 000000000..945f244d8 --- /dev/null +++ b/parity-crypto/benches/asym.rs @@ -0,0 +1,60 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use criterion::{Criterion, Bencher}; + +use parity_crypto::traits::asym::*; + +pub fn secp256k1(c: &mut Criterion) { + use parity_crypto::secp256k1::Secp256k1; + asym_bench::(c, "secp256k1".to_owned()) +} + +#[cfg(feature="alt")] +pub fn secp256k1_alt(c: &mut Criterion) { + use parity_crypto::secp256k1_alt::Secp256k1; + asym_bench::(c, "secp256k1_alt".to_owned()) +} + + + +fn asym_bench(c: &mut Criterion, name: String) { + + c.bench_function(&(name.clone() + "_sign_verify"), + |b: &mut Bencher| { + let mut sec_buf = vec![7; A::SECRET_SIZE]; + let message = vec![0;32]; + b.iter(|| { + let (secret, public) = A::keypair_from_slice(&mut sec_buf).unwrap(); + let signature = secret.sign(&message).unwrap(); + assert!(public.verify(&signature, &message).unwrap()); + }); + } + ); + + c.bench_function(&(name.clone() + "_sign_recover"), + |b: &mut Bencher| { + let mut sec_buf = vec![3; A::SECRET_SIZE]; + let message = vec![0;32]; + b.iter(|| { + let (secret, public) = A::keypair_from_slice(&mut sec_buf).unwrap(); + let signature = secret.sign(&message).unwrap(); + assert!(public == A::recover(&signature, &message).unwrap()); + }); + } + ); + +} diff --git a/parity-crypto/benches/bench.rs b/parity-crypto/benches/bench.rs new file mode 100644 index 000000000..a4e54524d --- /dev/null +++ b/parity-crypto/benches/bench.rs @@ -0,0 +1,62 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +extern crate parity_crypto; + +#[macro_use] +extern crate criterion; + +mod asym; + +use criterion::{Criterion, Bencher}; + +#[cfg(not(feature="alt"))] +criterion_group!(benches, input_len, asym::secp256k1); + +#[cfg(feature="alt")] +criterion_group!(benches, input_len, asym::secp256k1, asym::secp256k1_alt); + +criterion_main!(benches); + +/// general benches for multiple input size +fn input_len(c: &mut Criterion) { + + c.bench_function_over_inputs("ripemd", + |b: &mut Bencher, size: &usize| { + let data = vec![0u8; *size]; + b.iter(|| parity_crypto::digest::ripemd160(&data[..])); + }, + vec![100, 500, 1_000, 10_000, 100_000] + ); + + c.bench_function_over_inputs("aes_ctr", + |b: &mut Bencher, size: &usize| { + let data = vec![0u8; *size]; + let mut dest = vec![0; *size]; + let k = [0; 16]; + let iv = [0; 16]; + + b.iter(||{ + parity_crypto::aes::encrypt_128_ctr(&k[..], &iv[..], &data[..], &mut dest[..]).unwrap(); + // same as encrypt but add it just in case + parity_crypto::aes::decrypt_128_ctr(&k[..], &iv[..], &data[..], &mut dest[..]).unwrap(); + }); + }, + vec![100, 500, 1_000, 10_000, 100_000] + ); + +} diff --git a/parity-crypto/libsecp256k1/Cargo.toml b/parity-crypto/libsecp256k1/Cargo.toml new file mode 100644 index 000000000..aeda5c9b6 --- /dev/null +++ b/parity-crypto/libsecp256k1/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "libsecp256k1" +version = "0.0.1" +authors = ["Parity Technologies "] +repository = "https://github.com/paritytech/parity-common" +description = "Renaming crate for libsecp256k1." +license = "GPL-3.0" + +[dependencies] +libsecp256k1 = { version = "0.1" } diff --git a/parity-crypto/libsecp256k1/src/lib.rs b/parity-crypto/libsecp256k1/src/lib.rs new file mode 100644 index 000000000..a309d7b62 --- /dev/null +++ b/parity-crypto/libsecp256k1/src/lib.rs @@ -0,0 +1,23 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Renaming crate for libsecp256k1, this crate should be drop as soon as +//! 'renaming-crates' functionality makes it to stable. + + +extern crate secp256k1; + +pub use secp256k1::*; diff --git a/parity-crypto/src/aes.rs b/parity-crypto/src/aes.rs index 620ae4bcc..348801b6a 100644 --- a/parity-crypto/src/aes.rs +++ b/parity-crypto/src/aes.rs @@ -20,7 +20,7 @@ use block_modes::block_padding::ZeroPadding; use block_modes::{ Cbc, Ecb }; use raes::{ Aes128, Aes256 }; use aes_ctr::{ Aes128Ctr, Aes256Ctr }; -use aes_ctr::stream_cipher::{ NewFixStreamCipher, StreamCipherCore }; +use aes_ctr::stream_cipher::{ NewStreamCipher, SyncStreamCipher }; use error::SymmError; use raes::block_cipher_trait::generic_array::GenericArray; @@ -36,12 +36,16 @@ impl AesEcb256 { Ok(AesEcb256(Ecb::new_varkey(key)?)) } + /// In place encrypt a content without padding, the content length must be a multiple + /// of the block size. #[inline] pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { self.0.encrypt_nopad(content)?; Ok(()) } + /// In place decrypt a content without padding, the content length must be a multiple + /// of the block size. #[inline] pub fn decrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { self.0.decrypt_nopad(content)?; @@ -63,12 +67,16 @@ impl AesCtr256 { )) } + /// In place encrypt a content without padding, the content length must be a multiple + /// of the block size. #[inline] pub fn encrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { self.0.try_apply_keystream(content)?; Ok(()) } + /// In place decrypt a content without padding, the content length must be a multiple + /// of the block size. #[inline] pub fn decrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { self.0.try_apply_keystream(content)?; diff --git a/parity-crypto/src/error.rs b/parity-crypto/src/error.rs index 103875876..2fe122d0d 100644 --- a/parity-crypto/src/error.rs +++ b/parity-crypto/src/error.rs @@ -12,7 +12,7 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Parity. If not, see . +// along with Parity. If not, see . #[cfg(not(target_arch = "wasm32"))] use ring; @@ -34,19 +34,19 @@ quick_error! { from() } AsymShort(det: &'static str) { - description(det) + description(det) } AsymFull(e: Box) { - cause(&**e) - description(e.description()) - } + cause(&**e) + description(e.description()) + } } } impl Into for Error { - fn into(self) -> std::io::Error { - std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self)) - } + fn into(self) -> std::io::Error { + std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self)) + } } quick_error! { @@ -73,26 +73,6 @@ quick_error! { } } -/* -#[cfg(not(target_arch = "wasm32"))] -macro_rules! ring_error { - () => { - Ring(e: ring::error::Unspecified) { - display("symmetric crypto error") - cause(e) - from() - } - }; -} - -#[cfg(target_arch = "wasm32")] -macro_rules! ring_error { - () => { - }; -} -*/ - - #[cfg(target_arch = "wasm32")] quick_error! { #[derive(Debug)] diff --git a/parity-crypto/src/hmac.rs b/parity-crypto/src/hmac.rs index 6883040d2..0526367a4 100644 --- a/parity-crypto/src/hmac.rs +++ b/parity-crypto/src/hmac.rs @@ -88,35 +88,49 @@ pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { } +#[cfg(test)] +::tests_hmac!(); + +#[cfg(test)] +#[macro_export] +macro_rules! tests_hmac { + () => { + +pub mod test { + use super::*; + #[test] + fn simple_mac_and_verify() { + let input = b"Some bytes"; + let big_input = vec![7u8;2000]; + + let key1 = vec![3u8;64]; + let key2 = vec![4u8;128]; + + let sig_key1 = SigKey::sha256(&key1[..]); + let sig_key2 = SigKey::sha512(&key2[..]); + + let mut signer1 = Signer::with(&sig_key1); + let mut signer2 = Signer::with(&sig_key2); + + signer1.update(&input[..]); + for i in 0 .. big_input.len() / 33 { + signer2.update(&big_input[i*33..(i+1)*33]); + } + signer2.update(&big_input[(big_input.len() / 33)*33..]); + let sig1 = signer1.sign(); + assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); + let sig2 = signer2.sign(); + assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); + assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); + assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); + let verif_key1 = VerifyKey::sha256(&key1[..]); + let verif_key2 = VerifyKey::sha512(&key2[..]); + assert!(verify(&verif_key1, &input[..], &sig1[..])); + assert!(verify(&verif_key2, &big_input[..], &sig2[..])); -#[test] -fn simple_mac_and_verify() { - let input = b"Some bytes"; - let big_input = vec![7u8;2000]; - - let key1 = vec![3u8;64]; - let key2 = vec![4u8;128]; - - let sig_key1 = SigKey::sha256(&key1[..]); - let sig_key2 = SigKey::sha512(&key2[..]); - - let mut signer1 = Signer::with(&sig_key1); - let mut signer2 = Signer::with(&sig_key2); - - signer1.update(&input[..]); - for i in 0 .. big_input.len() / 33 { - signer2.update(&big_input[i*33..(i+1)*33]); } - signer2.update(&big_input[(big_input.len() / 33)*33..]); - let sig1 = signer1.sign(); - assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); - let sig2 = signer2.sign(); - assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); - assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); - assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); - let verif_key1 = VerifyKey::sha256(&key1[..]); - let verif_key2 = VerifyKey::sha512(&key2[..]); - assert!(verify(&verif_key1, &input[..], &sig1[..])); - assert!(verify(&verif_key2, &big_input[..], &sig2[..])); +} } +} + diff --git a/parity-crypto/src/hmac_alt.rs b/parity-crypto/src/hmac_alt.rs index cb5b1a563..023a3bb32 100644 --- a/parity-crypto/src/hmac_alt.rs +++ b/parity-crypto/src/hmac_alt.rs @@ -83,36 +83,5 @@ pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { ver.0.verify(sig).is_ok() } -#[test] -fn simple_mac_and_verify() { - use super::is_equal; - let input = b"Some bytes"; - let big_input = vec![7u8;2000]; - - let key1 = vec![3u8;64]; - let key2 = vec![4u8;128]; - - let sig_key1 = SigKey::sha256(&key1[..]); - let sig_key2 = SigKey::sha512(&key2[..]); - let mut signer1 = Signer::with(&sig_key1); - let mut signer2 = Signer::with(&sig_key2); - - signer1.update(&input[..]); - for i in 0 .. big_input.len() / 33 { - signer2.update(&big_input[i*33..(i+1)*33]); - } - signer2.update(&big_input[(big_input.len() / 33)*33..]); - let sig1 = signer1.sign(); - assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); - let sig2 = signer2.sign(); - assert!(is_equal(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..])); - - assert!(is_equal(&sig1[..], &sign(&sig_key1, &input[..])[..])); - assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); - let verif_key1 = VerifyKey::sha256(&key1[..]); - let verif_key2 = VerifyKey::sha512(&key2[..]); - assert!(verify(&verif_key1, &input[..], &sig1[..])); - assert!(verify(&verif_key2, &big_input[..], &sig2[..])); - - -} +#[cfg(test)] +::tests_hmac!(); diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 55f4dae16..5229d33a8 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -36,7 +36,7 @@ extern crate mem; /// reexport clear_on_drop crate pub mod clear_on_drop { - pub use mem::clear_on_drop::*; + pub use mem::clear_on_drop::*; } /// reexport `Memzero` from `mem` @@ -52,7 +52,7 @@ pub mod scrypt; pub mod digest; #[cfg(not(target_arch = "wasm32"))] pub mod hmac; -#[cfg(all(not(target_arch = "wasm32"), test))] +#[cfg(all(not(target_arch = "wasm32"), any(test, feature="alt")))] pub mod hmac_alt; #[path = "hmac_alt.rs"] #[cfg(target_arch = "wasm32")] @@ -62,14 +62,14 @@ pub mod hmac; #[cfg(not(target_arch = "wasm32"))] pub mod secp256k1; -#[cfg(all(not(target_arch = "wasm32"), test))] +#[cfg(all(not(target_arch = "wasm32"), any(test, feature="alt")))] pub mod secp256k1_alt; #[path = "secp256k1_alt.rs"] #[cfg(target_arch = "wasm32")] pub mod secp256k1; -#[cfg(all(not(target_arch = "wasm32"), test))] +#[cfg(all(not(target_arch = "wasm32"), any(test, feature="alt")))] pub mod pbkdf2_alt; #[cfg(not(target_arch = "wasm32"))] pub mod pbkdf2; diff --git a/parity-crypto/src/pbkdf2.rs b/parity-crypto/src/pbkdf2.rs index 9cc830716..84ccca6ac 100644 --- a/parity-crypto/src/pbkdf2.rs +++ b/parity-crypto/src/pbkdf2.rs @@ -27,12 +27,27 @@ pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) } -#[test] -fn basic_test() { - let mut dest = [0;32]; - let salt = [5;32]; - let secret = [7;32]; - sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); - let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; - assert_eq!(res, dest); + +#[cfg(test)] +::tests_pbkdf2!(); + +#[cfg(test)] +#[macro_export] +macro_rules! tests_pbkdf2 { + () => { + +mod test { + use super::*; + #[test] + fn basic_test() { + let mut dest = [0;32]; + let salt = [5;32]; + let secret = [7;32]; + sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); + let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; + assert_eq!(res, dest); + } +} + +} } diff --git a/parity-crypto/src/pbkdf2_alt.rs b/parity-crypto/src/pbkdf2_alt.rs index 2a8900ca6..18d0331e4 100644 --- a/parity-crypto/src/pbkdf2_alt.rs +++ b/parity-crypto/src/pbkdf2_alt.rs @@ -31,12 +31,7 @@ pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { self::pbkdf2::pbkdf2::>(sec.0, salt.0, iter as usize, &mut out[..]) } -#[test] -fn basic_test() { - let mut dest = [0;32]; - let salt = [5;32]; - let secret = [7;32]; - sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); - let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; - assert_eq!(res, dest); -} + +#[cfg(test)] +::tests_pbkdf2!(); + diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index f32ec541d..1f98a52c9 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -95,7 +95,7 @@ impl Drop for SecretKey { let len = self.0.len(); unsafe { let mut v = std::slice::from_raw_parts(self.0.as_mut_ptr(), len); - v.clear() + Clear::clear(&mut v); } } } @@ -111,6 +111,8 @@ impl Asym for Secp256k1 { const SECRET_SIZE: usize = SECRET_KEY_SIZE; + const KEYPAIR_INPUT_SIZE: usize = Self::SECRET_SIZE; + fn recover(signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; @@ -213,8 +215,8 @@ impl PublicKeyTrait for PublicKey { }*/ /// Should move to another trait. - fn to_compressed_vec(p: &Self) -> Self::VecRepr { - p.0.serialize_vec(&SECP256K1, true) + fn to_compressed_vec(&self) -> Self::VecRepr { + self.0.serialize_vec(&SECP256K1, true) } fn is_valid(&self) -> bool { @@ -280,11 +282,11 @@ impl FiniteField for Secp256k1 { } fn one_key() -> &'static Self::SecretKey { - &ONE_KEY + &ONE_KEY } fn zero_key() -> &'static Self::SecretKey { - &ZERO_KEY + &ZERO_KEY } fn minus_one_key() -> &'static Self::SecretKey { @@ -308,132 +310,10 @@ impl From for Error { } #[cfg(test)] -mod tests { - extern crate rand; - use ::traits::asym::*; - use super::{ - Secp256k1, - }; - use self::rand::OsRng; - use self::rand::Rng; - - #[test] - fn sign_val() { - let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let sec = Secp256k1::secret_from_slice(&sk).unwrap(); - let message = vec![2;32]; - let signature = sec.sign(&message).unwrap(); - assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); - } - - #[test] - fn sign_and_recover_public() { - let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; - osrng.fill_bytes(&mut sec_buf[..]); - let (secret, public) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let message = vec![2;32]; - let signature = secret.sign(&message).unwrap(); - assert_eq!(public, Secp256k1::recover(&signature, &message).unwrap()); - } - - #[test] - fn sign_and_verify_public() { - let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; - osrng.fill_bytes(&mut sec_buf[..]); - let (secret, public) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let message = vec![0;32]; - let signature = secret.sign(&message).unwrap(); - assert!(public.verify(&signature, &message).unwrap()); - } - - #[test] - fn public_addition() { - let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; - let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; - let mut pub1 = Secp256k1::public_from_slice(&pk1[..]).unwrap(); - let pub2 = Secp256k1::public_from_slice(&pk2[..]).unwrap(); - Secp256k1::public_add(&mut pub1, &pub2).unwrap(); - - assert_eq!(&pub1.as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); - } - - #[test] - fn public_multiplication() { - let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; - let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let mut pubk = Secp256k1::public_from_slice(&pk[..]).unwrap(); - let sec = Secp256k1::secret_from_slice(&sk[..]).unwrap(); - Secp256k1::public_mul(&mut pubk, &sec).unwrap(); - - assert_eq!(&pubk.as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); - } - - - #[test] - fn public_addition_is_commutative() { - let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; - osrng.fill_bytes(&mut sec_buf[..]); - let (_, public1) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - osrng.fill_bytes(&mut sec_buf[..]); - let (_, public2) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); +type AsymTest = Secp256k1; - let mut left = public1.clone(); - Secp256k1::public_add(&mut left, &public2).unwrap(); - - let mut right = public2.clone(); - Secp256k1::public_add(&mut right, &public1).unwrap(); - - assert_eq!(left, right); - } - - #[test] - fn public_addition_is_reversible_with_subtraction() { - let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; - osrng.fill_bytes(&mut sec_buf[..]); - let (_, public1) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - osrng.fill_bytes(&mut sec_buf[..]); - let (_, public2) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - - let mut sum = public1.clone(); - Secp256k1::public_add(&mut sum, &public2).unwrap(); - let mut op = public2.clone(); - Secp256k1::public_mul(&mut op, Secp256k1::minus_one_key()).unwrap(); - Secp256k1::public_add(&mut sum, &op).unwrap(); - - assert_eq!(sum, public1); - } - - - #[test] - fn multiplicating_secret_inversion_with_secret_gives_one() { - let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; - osrng.fill_bytes(&mut sec_buf[..]); - let (secret, _) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - - let mut inversion = secret.clone(); - Secp256k1::secret_inv(&mut inversion).unwrap(); - Secp256k1::secret_mul(&mut inversion, &secret).unwrap(); - assert_eq!(inversion, *Secp256k1::one_key()); - } - - #[test] - fn secret_inversion_is_reversible_with_inversion() { - let mut osrng = OsRng::new().expect("test"); - let mut sec_buf = vec![0; Secp256k1::SECRET_SIZE]; - osrng.fill_bytes(&mut sec_buf[..]); - let (secret, _) = Secp256k1::keypair_from_slice(&mut sec_buf).unwrap(); - let mut inversion = secret.clone(); - Secp256k1::secret_inv(&mut inversion).unwrap(); - Secp256k1::secret_inv(&mut inversion).unwrap(); - assert_eq!(inversion, secret); - } - -} +#[cfg(test)] +::tests_asym!(); /// Default implementation is only for parity-ethereum secret-store /// It would be good to remove it (there is a bit of refactoring). diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 7d22ffe9a..6b8289cd6 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -21,13 +21,22 @@ extern crate rand; use self::rand::Rng; use clear_on_drop::clear::Clear; -use clear_on_drop::ClearOnDrop; -use ::traits::asym::{PublicKey as PublicKeyTrait}; +use ::traits::asym::{ + Asym, + PublicKey as PublicKeyTrait, + SecretKey as SecretKeyTrait, + FixAsymSharedSecret, + FiniteField +}; + +use super::error::Error; + +pub struct Secp256k1; pub use self::secp256k1::{ - Error, - PublicKey, - SecretKey, + Error as InnerError, + PublicKey as PublicKeyInner, + SecretKey as SecretKeyInner, }; @@ -45,12 +54,16 @@ use self::secp256k1::curve::{ use self::secp256k1::curve::ECMULT_CONTEXT; -pub const SECRET_KEY_SIZE: usize = 32; + +const SIGN_SIZE: usize = 65; +const PUB_SIZE: usize = 64; +const SECRET_SIZE: usize = 32; const MINUS_ONE_BYTES: [u8;32] = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 186, 174, 220, 230, 175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 64]; const ONE_BYTES: [u8;32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; +const ZERO_BYTES: [u8;32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; /// The X coordinate of the generator (could get from lib AFFINE_G const but it is more convenient /// this way : could be default value of a trait) @@ -78,8 +91,10 @@ pub const CURVE_ORDER: [u8; 32] = [ ]; lazy_static! { - static ref MINUS_ONE_KEY: SecretKey = SecretKey::parse(&MINUS_ONE_BYTES).expect("static; qed"); - static ref ONE_KEY: SecretKey = SecretKey::parse(&ONE_BYTES).expect("static; qed"); + static ref MINUS_ONE_KEY: SecretKey = SecretKey::new(SecretKeyInner::parse(&MINUS_ONE_BYTES).expect("static; qed")); + static ref ONE_KEY: SecretKey = SecretKey::new(SecretKeyInner::parse(&ONE_BYTES).expect("static; qed")); + static ref ZERO_KEY: SecretKey = SecretKey::new(SecretKeyInner::parse(&ZERO_BYTES).expect("static; qed")); + static ref NULL_PUB_K: PublicKey = PublicKey::unsafe_empty(); } pub fn one_key() -> &'static SecretKey { @@ -91,369 +106,346 @@ pub fn minus_one_key() -> &'static SecretKey { } -/// secret size 32, message size 32 -pub fn sign(secret: &[u8], message: &[u8]) -> Result<[u8;65], Error> { - let mut buf = [0;32]; - buf.copy_from_slice(&message[..]); // panic on incorrect message size - let message = Message::parse(&buf); - buf.copy_from_slice(&secret[..]); // panic on incorrect secret size - let seckey = SecretKey::parse(&buf)?; - let (sig, rec_id) = secp256k1::sign(&message, &seckey)?; - let mut data_arr = [0; 65]; +//#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(Clone)] +pub struct PublicKey(PublicKeyInner,[u8;65]); - data_arr[0..64].copy_from_slice(&sig.serialize()); - data_arr[64] = rec_id.serialize(); - Ok(data_arr) -} - -/// public size 65, signature size 65, message size 32 -pub fn verify_public(public: &[u8], signature: &[u8], message: &[u8]) -> Result { +impl Eq for PublicKey { } - let mut buf = [0;32]; - buf.copy_from_slice(&message[..]); // panic on incorrect message size - let message = Message::parse(&buf); - let mut buf = [4;65]; - buf[1..65].copy_from_slice(&public[..]); // panic on incorrect public size - let pubkey = PublicKey::parse(&buf)?; - let mut buf = [0;64]; - buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size - let signature = Signature::parse(&buf); - - Ok(secp256k1::verify(&message, &signature, &pubkey)) +impl PartialEq for PublicKey { + fn eq(&self, other: &PublicKey) -> bool { + self.0.eq(&other.0) + } } -/// signature 65, message 32, return publickey 64 bit (no start 4) -pub fn recover(signature: &[u8], message: &[u8]) -> Result<[u8;64], Error> { - let mut buf = [0;32]; - buf.copy_from_slice(&message[..]); // panic on incorrect message size - let message = Message::parse(&buf); - let mut buf = [0;64]; - buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size - let recovery_id = RecoveryId::parse(signature[64])?; - let signature = Signature::parse(&buf); - let public_key = secp256k1::recover(&message, &signature, &recovery_id)?; - - let mut res = [0;64]; - res.copy_from_slice(&public_key.serialize()[1..65]); - - Ok(res) +impl std::fmt::Debug for PublicKey { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0.fmt(f) + } } -#[deprecated] -/// random secret key for rand 0.5 -pub fn random_sec(rng: &mut R) -> SecretKey { - loop { - let mut ret = [0u8; 32]; - rng.fill_bytes(&mut ret); - match secret_from_slice(&ret) { - Ok(key) => return key, - Err(_) => (), - } +impl PublicKey { + + fn new(inner: PublicKeyInner) -> Self { + let a_vec = inner.serialize(); + PublicKey(inner, a_vec) } -} + fn unsafe_empty() -> Self { + PublicKey(PublicKeyInner::from_secret_key(&ONE_KEY.0), [0u8;65]) + } -#[deprecated] -/// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. -/// The intent is to avoid depending on `Rng` trait. -pub fn generate_keypair(r: &mut impl Rng) -> (SecretKey, PublicKey) { - let secret_key = random_sec(r); - let public_key = PublicKey::from_secret_key(&secret_key); - (secret_key, public_key) } -/// create a key pair from byte value of the secret key, the calling function is responsible for -/// erasing the input of memory. -pub fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(SecretKey, PublicKey), Error> { - assert!(sk_bytes.len() == SECRET_KEY_SIZE); - let secret_key = secret_from_slice(sk_bytes)?; - let public_key = PublicKey::from_secret_key(&secret_key); - Ok((secret_key, public_key)) +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + &self.1[1 .. 1 + PUB_SIZE] + } } +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SecretKey(SecretKeyInner,[u8;32]); -/// warning this returns 64 byte vec (we skip the first byte of 65 byte more standard -/// representation) -pub fn public_to_vec(p: &PublicKey) -> impl AsRef<[u8]> { - let a_vec = p.serialize(); - a_vec[1..65].to_vec() +impl Drop for SecretKey { + fn drop(&mut self) { + // TODO find a way to clear secret + } } -pub fn public_is_valid(p: &PublicKey) -> bool { - // Check from other implementation only look for a non zero value in fields - // here we can - let aff: Affine = p.clone().into(); - aff.is_valid_var() +impl AsRef<[u8]> for SecretKey { + fn as_ref(&self) -> &[u8] { + &self.1[..SECRET_SIZE] + } } -/// ret size 33 -pub fn public_to_compressed_vec(p: &PublicKey) -> impl AsRef<[u8]> { - p.serialize_compressed().to_vec() -} -/// only for test (or make the result erasable) -pub fn secret_to_vec(p: &SecretKey) -> impl AsRef<[u8]> { - let mut b = p.serialize(); - let res = ClearOnDrop::new(b.to_vec()); - b.clear(); - res -} +impl SecretKey { -/// 32 sized slice -pub fn secret_from_slice(secret: &[u8]) -> Result { - let mut buf = [0u8;32]; - buf.copy_from_slice(&secret[..]); // panic on incorrect secret size - let res = SecretKey::parse(&buf)?; - buf.clear(); - Ok(res) -} + fn new(inner: SecretKeyInner) -> Self { + let a_vec = inner.serialize(); + SecretKey(inner, a_vec) + } -pub fn shared_secret(publ: &PublicKey, sec: &SecretKey) -> Result, Error> { - secp256k1::SharedSecret::new(publ, sec) } -/// using a shortened 64bit public key as input -pub fn public_from_slice(public_sec_raw: &[u8]) -> Result { - let mut buf = [4;65]; - buf[1..65].copy_from_slice(&public_sec_raw[..]); // panic on incorrect public size - PublicKey::parse(&buf) -} +impl Asym for Secp256k1 { + type PublicKey = PublicKey; + type SecretKey = SecretKey; -pub fn public_from_secret(s: &SecretKey) -> Result { - Ok(PublicKey::from_secret_key(&s)) -} + /// This is highly ethereum opignated + const SIGN_SIZE: usize = SIGN_SIZE; + /// Warning we use 64 bit pubsize (first bytes of 65 bit representation is 4). + const PUB_SIZE: usize = PUB_SIZE; -fn aff_to_public(aff_pub: &mut Affine) -> Result { - let mut buff = [4;65]; - let mut buff2 = [0;32]; - aff_pub.x.normalize(); - aff_pub.x.fill_b32(&mut buff2); - buff[1..33].copy_from_slice(&buff2[..]); - aff_pub.y.normalize(); - aff_pub.y.fill_b32(&mut buff2); - buff[33..65].copy_from_slice(&buff2[..]); - PublicKey::parse(&buff) + const SECRET_SIZE: usize = SECRET_SIZE; -} + const KEYPAIR_INPUT_SIZE: usize = Self::SECRET_SIZE; -pub fn public_add(pub_key: PublicKey, other_public: &PublicKey) -> Result { - let mut aff_pub: Affine = pub_key.into(); - let mut aff_pub_j = Jacobian::default(); - aff_pub_j.set_ge(&aff_pub); - let aff_pub_other: Affine = other_public.clone().into(); - let res_j = aff_pub_j.add_ge(&aff_pub_other); - aff_pub.set_gej(&res_j); - aff_to_public(&mut aff_pub) -} + fn recover(signature: &[u8], message: &[u8]) -> Result { + let mut buf = [0;32]; + buf.copy_from_slice(&message[..]); // panic on incorrect message size + let message = Message::parse(&buf); + let mut buf = [0;64]; + buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size + let recovery_id = RecoveryId::parse(signature[64])?; + let signature = Signature::parse(&buf); + let public_key = secp256k1::recover(&message, &signature, &recovery_id)?; + Ok(PublicKey::new(public_key)) + } -struct SecretScalar(pub Scalar); -impl Drop for SecretScalar { - fn drop(&mut self) { - self.0.clear(); + /// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. + /// The intent is to avoid depending on `Rng` trait. + fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey) { + let secret_key = random_sec(r); + let public_key = PublicKeyInner::from_secret_key(&secret_key.0); + (secret_key, PublicKey::new(public_key)) } -} -pub fn public_mul(pub_key: PublicKey, sec_key: &SecretKey) -> Result { -/* let mut sec_scal = Scalar::default(); - sec_scal.set_b32(&sec_key.serialize());*/ - - let sec_scal = SecretScalar(sec_key.clone().into()); - let mut pub_aff: Affine = pub_key.into(); - let mut pub_jac = Jacobian::default(); - pub_jac.set_ge(&pub_aff); - - //ECMULT_GEN_CONTEXT.ecmult_gen(&mut pub_jac, &sec_scal); - //pub_aff.set_gej(&pub_jac); - let mut zero = Scalar::default(); - zero.set_int(0); - let mut res = Jacobian::default(); - ECMULT_CONTEXT.ecmult(&mut res, &pub_jac, &sec_scal.0, &zero); - pub_aff.set_gej(&res); - aff_to_public(&mut pub_aff) -} + /// create a key pair from byte value of the secret key, the calling function is responsible for + /// erasing the input of memory. + fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error> { + assert!(sk_bytes.len() == SECRET_SIZE); + let secret_key = Self::secret_from_slice(sk_bytes)?; + let public_key = Self::public_from_secret(&secret_key)?; + Ok((secret_key, public_key)) + } -/* private inner method but this would avoid a scalar instantiation -fn mul_in_place_scalar(a: &mut Scalar, b: &Scalar) { - let mut l = [0u32; 16]; - a.mul_512(b, &mut l); - a.reduce_512(&l); -} -*/ + fn public_from_secret(s: &Self::SecretKey) -> Result { + Ok(PublicKey::new(PublicKeyInner::from_secret_key(&s.0))) + } -pub fn secret_mul(sec_key: SecretKey, other_sec_key: &SecretKey) -> Result { - let sec_scal = SecretScalar(sec_key.clone().into()); - let other_sec_scal = SecretScalar(other_sec_key.clone().into()); - // we could use * operator instead. - let mut res = SecretScalar(Scalar::default()); - res.0.mul_in_place(&sec_scal.0, &other_sec_scal.0); - SecretKey::parse(&res.0.b32()) -} + /// using a shortened 64bit public key as input + fn public_from_slice(public_sec_raw: &[u8]) -> Result { + + let pdata = { + let mut temp = [4u8; PUB_SIZE + 1]; + (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); + temp + }; + Ok(PublicKey::new(PublicKeyInner::parse(&pdata)?)) + } + + fn secret_from_slice(secret: &[u8]) -> Result { + let mut buf = [0;32]; + buf[..].copy_from_slice(&secret[..SECRET_SIZE]); + let res = SecretKey::new(SecretKeyInner::parse(&buf)?); + Clear::clear(&mut buf); + Ok(res) + } -pub fn secret_add(sec_key: SecretKey, other_sec_key: &SecretKey) -> Result { - let sec_scal = SecretScalar(sec_key.clone().into()); - let other_sec_scal = SecretScalar(other_sec_key.clone().into()); - // we could use + operator instead. - let mut res = SecretScalar(Scalar::default()); - res.0.add_in_place(&sec_scal.0, &other_sec_scal.0); - SecretKey::parse(&res.0.b32()) -} -pub fn secret_inv(sec_key: SecretKey) -> Result { - let sec_scal = SecretScalar(sec_key.clone().into()); - let mut res = SecretScalar(Scalar::default()); - res.0.inv_in_place(&sec_scal.0); - SecretKey::parse(&res.0.b32()) } -/* impl PublicKeyTrait for PublicKey { type VecRepr = Vec; - fn to_vec(&self) -> Self::VecRepr { - unimplemented!() - } - /// Should move to another trait. - fn to_compressed_vec(p: &Self) -> Self::VecRepr { - unimplemented!() + fn to_compressed_vec(&self) -> Self::VecRepr { + self.0.serialize_compressed().to_vec() } fn is_valid(&self) -> bool { - unimplemented!() + // Check from other implementation only look for a non zero value in fields + // here we can + let aff: Affine = self.0.clone().into(); + aff.is_valid_var() } fn verify(&self, signature: &[u8], message: &[u8]) -> Result { - unimplemented!() + let mut buf = [0;32]; + buf.copy_from_slice(&message[..]); // panic on incorrect message size + let message = Message::parse(&buf); + let mut buf = [0;64]; + buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size + let signature = Signature::parse(&buf); + + Ok(secp256k1::verify(&message, &signature, &self.0)) } } -*/ - -//#[test] failing test will make it difficulte to use secret-store -fn zeroed_pk() { - let mut val = [0;65]; - val[0] = 4; - assert!(PublicKey::parse(&val).is_ok()); -} +impl SecretKeyTrait for SecretKey { + //type VecRepr = ClearOnDrop>; -#[cfg(test)] -mod tests { - extern crate rand; - use super::{ - sign, - secret_from_slice, - verify_public, - recover, - generate_keypair, - public_to_vec, - secret_to_vec, - public_add, - public_from_slice, - public_mul, - minus_one_key, - secret_mul, - secret_inv, - one_key, - }; - use self::rand::OsRng; + fn sign(&self, message: &[u8]) -> Result, Error> { - #[test] - fn sign_val() { - let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let message = vec![2;32]; - let signature = sign(&sk[..], &message).unwrap(); - assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); + let mut buf = [0;32]; + buf.copy_from_slice(&message[..]); // panic on incorrect message size + let message = Message::parse(&buf); + let (sig, rec_id) = secp256k1::sign(&message, &self.0)?; + let mut data_arr = vec![0; 65]; + data_arr[0..64].copy_from_slice(&sig.serialize()); + data_arr[64] = rec_id.serialize(); + Ok(data_arr) } - #[test] - fn sign_and_recover_public() { - let mut osrng = OsRng::new().expect("test"); - let (secret, public) = generate_keypair(&mut osrng); - let message = vec![2;32]; - let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); - assert_eq!(&public_to_vec(&public).as_ref()[..], &recover(&signature, &message).unwrap()[..]); +} + +/// random secret key for rand 0.5 +fn random_sec(rng: &mut R) -> SecretKey { + loop { + let mut ret = [0u8; 32]; + rng.fill_bytes(&mut ret); + + match Secp256k1::secret_from_slice(&ret) { + Ok(key) => return key, + Err(_) => (), + } } +} - #[test] - fn sign_and_verify_public() { - let mut osrng = OsRng::new().expect("test"); - let (secret, public) = generate_keypair(&mut osrng); - let message = vec![0;32]; - let signature = sign(secret_to_vec(&secret).as_ref(), &message).unwrap(); - assert!(verify_public(&public_to_vec(&public).as_ref()[..], &signature, &message).unwrap()); +impl FixAsymSharedSecret for SecretKey { + type Other = PublicKey; + type Result = SharedSecretAsRef; + + fn shared_secret(&self, publ: &Self::Other) -> Result { + let shared = secp256k1::SharedSecret::new(&publ.0, &self.0)?; + Ok(SharedSecretAsRef(shared)) } - #[test] - fn public_addition() { - let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; - let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; - let pub1 = public_from_slice(&pk1[..]).unwrap(); - let pub2 = public_from_slice(&pk2[..]).unwrap(); - let res = public_add(pub1, &pub2).unwrap(); +} + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct SharedSecretAsRef(pub secp256k1::SharedSecret); - assert_eq!(&public_to_vec(&res).as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); +impl AsRef<[u8]> for SharedSecretAsRef { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() } +} + +fn aff_to_public(aff_pub: &mut Affine) -> Result { + let mut buff = [4;65]; + let mut buff2 = [0;32]; + aff_pub.x.normalize(); + aff_pub.x.fill_b32(&mut buff2); + buff[1..33].copy_from_slice(&buff2[..]); + aff_pub.y.normalize(); + aff_pub.y.fill_b32(&mut buff2); + buff[33..65].copy_from_slice(&buff2[..]); + Ok(PublicKeyInner::parse(&buff)?) +} - #[test] - fn public_multiplication() { - let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; - let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; - let pubk = public_from_slice(&pk[..]).unwrap(); - let sec = secret_from_slice(&sk[..]).unwrap(); - let res = public_mul(pubk, &sec).unwrap(); +struct SecretScalar(pub Scalar); - assert_eq!(&public_to_vec(&res).as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); +impl Drop for SecretScalar { + fn drop(&mut self) { + self.0.clear(); } +} +/* private inner method but this would avoid a scalar instantiation +fn mul_in_place_scalar(a: &mut Scalar, b: &Scalar) { + let mut l = [0u32; 16]; + a.mul_512(b, &mut l); + a.reduce_512(&l); +} +*/ - #[test] - fn public_addition_is_commutative() { - let mut osrng = OsRng::new().expect("test"); - let (_, public1) = generate_keypair(&mut osrng); - let (_, public2) = generate_keypair(&mut osrng); +impl FiniteField for Secp256k1 { + + fn generator_x() -> &'static[u8] { &GENERATOR_X[..] } + fn generator_y() -> &'static[u8] { &GENERATOR_Y[..] } + fn curve_order() -> &'static[u8] { &CURVE_ORDER[..] } + + fn public_mul(pub_key: &mut Self::PublicKey, sec_key: &Self::SecretKey) -> Result<(), Error> { + let sec_scal = SecretScalar(sec_key.0.clone().into()); + let mut pub_aff: Affine = pub_key.0.clone().into(); + let mut pub_jac = Jacobian::default(); + pub_jac.set_ge(&pub_aff); + //ECMULT_GEN_CONTEXT.ecmult_gen(&mut pub_jac, &sec_scal); + //pub_aff.set_gej(&pub_jac); + let mut zero = Scalar::default(); + zero.set_int(0); + let mut res = Jacobian::default(); + ECMULT_CONTEXT.ecmult(&mut res, &pub_jac, &sec_scal.0, &zero); + pub_aff.set_gej(&res); + *pub_key = PublicKey::new(aff_to_public(&mut pub_aff)?); + Ok(()) + } - let left = public_add(public1.clone(), &public2).unwrap(); + fn public_add(pub_key: &mut Self::PublicKey, other_public: &Self::PublicKey) -> Result<(), Error> { + let mut aff_pub: Affine = pub_key.0.clone().into(); + let mut aff_pub_j = Jacobian::default(); + aff_pub_j.set_ge(&aff_pub); + let aff_pub_other: Affine = other_public.0.clone().into(); + let res_j = aff_pub_j.add_ge(&aff_pub_other); + aff_pub.set_gej(&res_j); + *pub_key = PublicKey::new(aff_to_public(&mut aff_pub)?); - let right = public_add(public2.clone(), &public1).unwrap(); + Ok(()) + } - assert_eq!(left, right); + fn secret_mul(sec_key: &mut Self::SecretKey, other_sec_key: &Self::SecretKey) -> Result<(), Error> { + let sec_scal = SecretScalar(sec_key.0.clone().into()); + let other_sec_scal = SecretScalar(other_sec_key.0.clone().into()); + // we could use * operator instead. + let mut res = SecretScalar(Scalar::default()); + res.0.mul_in_place(&sec_scal.0, &other_sec_scal.0); + *sec_key = SecretKey::new(SecretKeyInner::parse(&res.0.b32())?); + Ok(()) } - #[test] - fn public_addition_is_reversible_with_subtraction() { - let mut osrng = OsRng::new().expect("test"); - let (_, public1) = generate_keypair(&mut osrng); - let (_, public2) = generate_keypair(&mut osrng); + fn secret_add(sec_key: &mut Self::SecretKey, other_sec_key: &Self::SecretKey) -> Result<(), Error> { + let sec_scal = SecretScalar(sec_key.0.clone().into()); + let other_sec_scal = SecretScalar(other_sec_key.0.clone().into()); + // we could use + operator instead. + let mut res = SecretScalar(Scalar::default()); + res.0.add_in_place(&sec_scal.0, &other_sec_scal.0); + *sec_key = SecretKey::new(SecretKeyInner::parse(&res.0.b32())?); + Ok(()) + } - let sum = public_add(public1.clone(), &public2).unwrap(); - let op = public_mul(public2.clone(), minus_one_key()).unwrap(); - let sum = public_add(sum, &op).unwrap(); + fn secret_inv(sec_key: &mut Self::SecretKey) -> Result<(), Error> { + let sec_scal = SecretScalar(sec_key.0.clone().into()); + let mut res = SecretScalar(Scalar::default()); + res.0.inv_in_place(&sec_scal.0); + *sec_key = SecretKey::new(SecretKeyInner::parse(&res.0.b32())?); + Ok(()) + } - assert_eq!(sum, public1); + fn one_key() -> &'static Self::SecretKey { + &ONE_KEY } + fn zero_key() -> &'static Self::SecretKey { + &ZERO_KEY + } - #[test] - fn multiplicating_secret_inversion_with_secret_gives_one() { - let mut osrng = OsRng::new().expect("test"); - let (secret, _) = generate_keypair(&mut osrng); - let inversion = secret_inv(secret.clone()).unwrap(); - let inversion = secret_mul(inversion, &secret).unwrap(); - assert_eq!(inversion, *one_key()); + fn minus_one_key() -> &'static Self::SecretKey { + &MINUS_ONE_KEY } - #[test] - fn secret_inversion_is_reversible_with_inversion() { - let mut osrng = OsRng::new().expect("test"); - let (secret, _) = generate_keypair(&mut osrng); - let inversion = secret_inv(secret.clone()).unwrap(); - let inversion = secret_inv(inversion).unwrap(); - assert_eq!(inversion, secret); +} + +impl From for Error { + fn from(err: InnerError) -> Self { + match err { + InnerError::InvalidSecretKey => Error::AsymShort("Invalid secret"), + InnerError::InvalidRecoveryId => Error::AsymShort("Invalid recovery id"), + InnerError::InvalidPublicKey => Error::AsymShort("Invalid public"), + InnerError::InvalidSignature => Error::AsymShort("Invalid EC signature"), + InnerError::InvalidMessage => Error::AsymShort("Invalid AES message"), + } } +} +#[cfg(test)] +type AsymTest = Secp256k1; + +#[cfg(test)] +::tests_asym!(); + +/// Default implementation is only for parity-ethereum secret-store +/// It would be good to remove it (there is a bit of refactoring). +/// Therefore the constraint is not explicit. +/// Please note that it is an invalid publickey. +impl Default for PublicKey { + fn default() -> Self { + NULL_PUB_K.clone() + } } diff --git a/parity-crypto/src/traits/asym.rs b/parity-crypto/src/traits/asym.rs new file mode 100644 index 000000000..c07a6c0a9 --- /dev/null +++ b/parity-crypto/src/traits/asym.rs @@ -0,0 +1,277 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! asymetric trait + +extern crate rand; + +use ::error::Error; +use self::rand::Rng; + +/// Trait for asymetric crypto +pub trait Asym { + + /// Signature expected size in bytes + const SIGN_SIZE: usize; + + /// Public key expected size in bytes + const PUB_SIZE: usize; + + /// Private key expected size in bytes + const SECRET_SIZE: usize; + + /// Size of secure random input require + /// to generate a keypair + const KEYPAIR_INPUT_SIZE: usize; + + /// Associated type for Public Key + type PublicKey: PublicKey; + + /// Associated type for Private key + type SecretKey: SecretKey; + + /// Recover a public key from a signature over a message + /// This function could move to a more specific trait in the future + fn recover(signature: &[u8], message: &[u8]) -> Result; + + /// Generate a key pair from a random function. + #[deprecated] + fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey); + + /// Generate a keypair from a random input + fn keypair_from_slice(bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error>; + + /// Generate a public key from a secret key + /// This function could move to a more specific trait in the future + fn public_from_secret(s: &Self::SecretKey) -> Result; + + /// Instantiate a public key from its byte representation + fn public_from_slice(bytes: &[u8]) -> Result; + + /// Instantiate a private key from its byte representation + fn secret_from_slice(bytes: &[u8]) -> Result; + +} + + +pub trait FixAsymSharedSecret: SecretKey { + type Other; + type Result: AsRef<[u8]>; + + // TODO replace by Result> when supported + fn shared_secret(&self, publ: &Self::Other) -> Result; + +} + +/// Some Finite field arithmetic primitives. +pub trait FiniteField: Asym { + + fn public_mul(_pub_key: &mut Self::PublicKey, _sec_key: &Self::SecretKey) -> Result<(), Error>; + + fn public_add(_pub_key: &mut Self::PublicKey, _other_public: &Self::PublicKey) -> Result<(), Error>; + + fn secret_mul(_sec_key: &mut Self::SecretKey, _other_secret: &Self::SecretKey) -> Result<(), Error>; + + fn secret_add(_sec_key: &mut Self::SecretKey, _other_secret: &Self::SecretKey) -> Result<(), Error>; + + fn secret_inv(_sec_key: &mut Self::SecretKey) -> Result<(), Error>; + + fn zero_key() -> &'static Self::SecretKey; + + fn one_key() -> &'static Self::SecretKey; + + fn minus_one_key() -> &'static Self::SecretKey; + + // those fn should not be exposed and function using them instead + fn generator_x() -> &'static[u8]; + fn generator_y() -> &'static[u8]; + fn curve_order() -> &'static[u8]; +} + + +/// PublicKey. +/// Contraint AsRef<[u8]>` is not memory efficient for ffi. +/// Keeping in mind that the trait is here to make thing easier +/// in a parity context. We assert that for use cases such as parity ethereum it is very usefull. +/// In the future a switch to having only a function returning `impl AsRef<[u8]>` +/// could be done but at the time it involves moving a huge amount of logic to this crate. +pub trait PublicKey: Sized + Eq + PartialEq + Clone + AsRef<[u8]> { + type VecRepr: AsRef<[u8]>; + + /// Should move to another trait. + fn to_compressed_vec(&self) -> Self::VecRepr; + + /// Compatibility, this should disappear, public key should always be valid. + fn is_valid(&self) -> bool; + + fn verify(&self, signature: &[u8], message: &[u8]) -> Result; + +} + +/// SecretKey (Private key). +pub trait SecretKey: Sized + Eq + PartialEq + Clone + AsRef<[u8]> { + + fn sign(&self, message: &[u8]) -> Result, Error>; + +} + + +/// This macro is callable only if the parent trait +/// contains a type `AsymTest` that implements `asym`. +#[cfg(test)] +#[macro_export] +macro_rules! tests_asym { + () => { + +#[cfg(test)] +mod tests { + extern crate rand; + use super::AsymTest; + use ::traits::asym::*; + use self::rand::OsRng; + use self::rand::Rng; + + #[test] + fn sign_val() { + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let sec = AsymTest::secret_from_slice(&sk).unwrap(); + let message = vec![2;32]; + let signature = sec.sign(&message).unwrap(); + assert_eq!(&signature[..], &[88, 96, 150, 252, 139, 37, 138, 196, 9, 30, 22, 98, 125, 20, 223, 16, 221, 46, 42, 225, 164, 71, 221, 37, 81, 9, 58, 3, 31, 245, 121, 110, 0, 248, 154, 65, 12, 193, 151, 151, 236, 69, 230, 56, 39, 161, 124, 1, 30, 20, 130, 5, 174, 75, 254, 199, 5, 119, 39, 223, 20, 116, 11, 229, 0][..]); + } + + #[test] + fn sign_and_recover_public() { + let mut osrng = OsRng::new().expect("test"); + let mut sec_buf = vec![0; AsymTest::SECRET_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, public) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + let message = vec![2;32]; + let signature = secret.sign(&message).unwrap(); + assert_eq!(public, AsymTest::recover(&signature, &message).unwrap()); + } + + #[test] + fn sign_and_verify_public() { + let mut osrng = OsRng::new().expect("test"); + let mut sec_buf = vec![0; AsymTest::SECRET_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, public) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + let message = vec![0;32]; + let signature = secret.sign(&message).unwrap(); + assert!(public.verify(&signature, &message).unwrap()); + } + + #[test] + fn public_addition() { + let pk1 = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let pk2 = [40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 195, 194, 16, 229, 39]; + let mut pub1 = AsymTest::public_from_slice(&pk1[..]).unwrap(); + let pub2 = AsymTest::public_from_slice(&pk2[..]).unwrap(); + AsymTest::public_add(&mut pub1, &pub2).unwrap(); + + assert_eq!(&pub1.as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + } + + #[test] + fn public_multiplication() { + let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let mut pubk = AsymTest::public_from_slice(&pk[..]).unwrap(); + let sec = AsymTest::secret_from_slice(&sk[..]).unwrap(); + AsymTest::public_mul(&mut pubk, &sec).unwrap(); + + assert_eq!(&pubk.as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + } + + + #[test] + fn public_addition_is_commutative() { + let mut osrng = OsRng::new().expect("test"); + let mut sec_buf = vec![0; AsymTest::SECRET_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public1) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public2) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + + let mut left = public1.clone(); + AsymTest::public_add(&mut left, &public2).unwrap(); + + let mut right = public2.clone(); + AsymTest::public_add(&mut right, &public1).unwrap(); + + assert_eq!(left, right); + } + + #[test] + fn public_addition_is_reversible_with_subtraction() { + let mut osrng = OsRng::new().expect("test"); + let mut sec_buf = vec![0; AsymTest::SECRET_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public1) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + osrng.fill_bytes(&mut sec_buf[..]); + let (_, public2) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + + let mut sum = public1.clone(); + AsymTest::public_add(&mut sum, &public2).unwrap(); + let mut op = public2.clone(); + AsymTest::public_mul(&mut op, AsymTest::minus_one_key()).unwrap(); + AsymTest::public_add(&mut sum, &op).unwrap(); + + assert_eq!(sum, public1); + } + + + #[test] + fn multiplicating_secret_inversion_with_secret_gives_one() { + let mut osrng = OsRng::new().expect("test"); + let mut sec_buf = vec![0; AsymTest::SECRET_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, _) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + + let mut inversion = secret.clone(); + AsymTest::secret_inv(&mut inversion).unwrap(); + AsymTest::secret_mul(&mut inversion, &secret).unwrap(); + assert_eq!(inversion, *AsymTest::one_key()); + } + + #[test] + fn secret_inversion_is_reversible_with_inversion() { + let mut osrng = OsRng::new().expect("test"); + let mut sec_buf = vec![0; AsymTest::SECRET_SIZE]; + osrng.fill_bytes(&mut sec_buf[..]); + let (secret, _) = AsymTest::keypair_from_slice(&mut sec_buf).unwrap(); + let mut inversion = secret.clone(); + AsymTest::secret_inv(&mut inversion).unwrap(); + AsymTest::secret_inv(&mut inversion).unwrap(); + assert_eq!(inversion, secret); + } + + #[test] + fn serialize_keys() { + let pk = [126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 112, 77, 239, 98, 135, 132]; + let sk = [213, 68, 220, 102, 106, 158, 142, 136, 198, 84, 32, 178, 49, 72, 194, 143, 116, 165, 155, 122, 20, 120, 169, 29, 129, 128, 206, 190, 48, 122, 97, 52]; + let ck = [2, 126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115]; + let pubk = AsymTest::public_from_slice(&pk[..]).unwrap(); + let sec = AsymTest::secret_from_slice(&sk[..]).unwrap(); + assert!(pubk.as_ref() == &pk[..]); + assert!(sec.as_ref() == &sk[..]); + assert!(AsRef::<[u8]>::as_ref(&pubk.to_compressed_vec()) == &ck[..]); + } +} + +} +} diff --git a/parity-crypto/src/traits/mod.rs b/parity-crypto/src/traits/mod.rs new file mode 100644 index 000000000..3b0feb0f9 --- /dev/null +++ b/parity-crypto/src/traits/mod.rs @@ -0,0 +1,26 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + + +//! trait module. Those traits expose current crypto usage in parity crates, event if they may evolve to +//! better prototype, that is not the current target. +//! The goal of those trait is to allow faster and more reliable switch of crypto dependencies. +//! It is done by running tests at a trait level. +//! Traits are only considering monomorphic usage (`dyn` usage is not covered). + +pub mod asym; + From 6b5e6fac327a57c963467376bddc3be7867a9a2c Mon Sep 17 00:00:00 2001 From: cheme Date: Wed, 14 Nov 2018 17:55:23 +0100 Subject: [PATCH 26/39] No as_ref buffer usage. --- parity-crypto/src/secp256k1.rs | 52 +++++----------------- parity-crypto/src/secp256k1_alt.rs | 70 ++++++++---------------------- parity-crypto/src/traits/asym.rs | 26 +++++++---- 3 files changed, 46 insertions(+), 102 deletions(-) diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index 1f98a52c9..ec5453922 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -23,6 +23,7 @@ extern crate secp256k1; extern crate arrayvec; extern crate rand; use clear_on_drop::clear::Clear; +use clear_on_drop::ClearOnDrop; use self::arrayvec::ArrayVec; use self::rand::Rng; @@ -68,22 +69,16 @@ const PUB_SIZE: usize = 64; // not vec size could be reduce to 64 (higher instantiation cost) #[derive(PartialEq, Eq, Debug, Clone)] -pub struct PublicKey(PublicKeyInner, ArrayVec<[u8;72]>); +pub struct PublicKey(PublicKeyInner); impl PublicKey { fn new(inner: PublicKeyInner) -> Self { - let a_vec = inner.serialize_vec(&SECP256K1, false); - PublicKey(inner, a_vec) - } - - fn refresh(&mut self) { - let a_vec = self.0.serialize_vec(&SECP256K1, false); - self.1 = a_vec; + PublicKey(inner) } fn unsafe_empty() -> Self { - PublicKey(PublicKeyInner::new(), [0;72].into()) + PublicKey(PublicKeyInner::new()) } } @@ -118,11 +113,6 @@ impl Asym for Secp256k1 { let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; Ok(PublicKey::new(pubkey)) - //let serialized = pubkey.serialize_vec(context, false); - - //let mut res = vec![0;PUB_SIZE]; - //res[..].copy_from_slice(&serialized[1..PUB_SIZE + 1]); - //Ok(res) } @@ -162,8 +152,6 @@ impl Asym for Secp256k1 { Ok(SecretKey(SecretKeyInner::from_slice(&SECP256K1, secret)?)) } - - } impl FixAsymSharedSecret for SecretKey { @@ -178,7 +166,7 @@ impl FixAsymSharedSecret for SecretKey { } impl SecretKeyTrait for SecretKey { - //type VecRepr = ClearOnDrop>; + type VecRepr = ClearOnDrop>; fn sign(&self, message: &[u8]) -> Result, Error> { let context = &SECP256K1; @@ -192,30 +180,25 @@ impl SecretKeyTrait for SecretKey { Ok(data_arr) } - /*fn to_vec(&self) -> Self::VecRepr { + fn to_vec(&self) -> Self::VecRepr { ClearOnDrop::new(self.0[..].to_vec()) - }*/ - -} - -impl AsRef<[u8]> for SecretKey { - fn as_ref(&self) -> &[u8] { - &self.0[..] } + } impl PublicKeyTrait for PublicKey { type VecRepr = ArrayVec<[u8; 72]>; + type CompVecRepr = ArrayVec<[u8; 72]>; - /*fn to_vec(&self) -> Self::VecRepr { - let mut a_vec = self.serialize_vec(&SECP256K1, false); + fn to_vec(&self) -> Self::VecRepr { + let mut a_vec = self.0.serialize_vec(&SECP256K1, false); let _ = a_vec.drain(PUB_SIZE + 1..); a_vec.remove(0); a_vec - }*/ + } /// Should move to another trait. - fn to_compressed_vec(&self) -> Self::VecRepr { + fn to_compressed_vec(&self) -> Self::CompVecRepr { self.0.serialize_vec(&SECP256K1, true) } @@ -237,15 +220,6 @@ impl PublicKeyTrait for PublicKey { } -// warning it returns PUB_SIZE byte vec (we skip the first byte of SIGN_SIZE byte more standard -// representation) -impl AsRef<[u8]> for PublicKey { - fn as_ref(&self) -> &[u8] { - &self.1[1 .. 1 + PUB_SIZE] - } -} - - pub struct Secp256k1; impl FiniteField for Secp256k1 { @@ -256,13 +230,11 @@ impl FiniteField for Secp256k1 { fn public_mul(pub_key: &mut Self::PublicKey, sec_key: &Self::SecretKey) -> Result<(), Error> { pub_key.0.mul_assign(&SECP256K1, &sec_key.0)?; - pub_key.refresh(); Ok(()) } fn public_add(pub_key: &mut Self::PublicKey, other_public: &Self::PublicKey) -> Result<(), Error> { pub_key.0.add_assign(&SECP256K1, &other_public.0)?; - pub_key.refresh(); Ok(()) } diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 6b8289cd6..e70186853 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -21,6 +21,7 @@ extern crate rand; use self::rand::Rng; use clear_on_drop::clear::Clear; +use clear_on_drop::ClearOnDrop; use ::traits::asym::{ Asym, PublicKey as PublicKeyTrait, @@ -94,7 +95,6 @@ lazy_static! { static ref MINUS_ONE_KEY: SecretKey = SecretKey::new(SecretKeyInner::parse(&MINUS_ONE_BYTES).expect("static; qed")); static ref ONE_KEY: SecretKey = SecretKey::new(SecretKeyInner::parse(&ONE_BYTES).expect("static; qed")); static ref ZERO_KEY: SecretKey = SecretKey::new(SecretKeyInner::parse(&ZERO_BYTES).expect("static; qed")); - static ref NULL_PUB_K: PublicKey = PublicKey::unsafe_empty(); } pub fn one_key() -> &'static SecretKey { @@ -106,47 +106,19 @@ pub fn minus_one_key() -> &'static SecretKey { } -//#[derive(PartialEq, Eq, Debug, Clone)] -#[derive(Clone)] -pub struct PublicKey(PublicKeyInner,[u8;65]); - -impl Eq for PublicKey { } - - -impl PartialEq for PublicKey { - fn eq(&self, other: &PublicKey) -> bool { - self.0.eq(&other.0) - } -} - -impl std::fmt::Debug for PublicKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - self.0.fmt(f) - } -} - +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct PublicKey(PublicKeyInner); impl PublicKey { fn new(inner: PublicKeyInner) -> Self { - let a_vec = inner.serialize(); - PublicKey(inner, a_vec) - } - - fn unsafe_empty() -> Self { - PublicKey(PublicKeyInner::from_secret_key(&ONE_KEY.0), [0u8;65]) + PublicKey(inner) } } -impl AsRef<[u8]> for PublicKey { - fn as_ref(&self) -> &[u8] { - &self.1[1 .. 1 + PUB_SIZE] - } -} - #[derive(PartialEq, Eq, Debug, Clone)] -pub struct SecretKey(SecretKeyInner,[u8;32]); +pub struct SecretKey(SecretKeyInner); impl Drop for SecretKey { fn drop(&mut self) { @@ -154,18 +126,10 @@ impl Drop for SecretKey { } } -impl AsRef<[u8]> for SecretKey { - fn as_ref(&self) -> &[u8] { - &self.1[..SECRET_SIZE] - } -} - - impl SecretKey { fn new(inner: SecretKeyInner) -> Self { - let a_vec = inner.serialize(); - SecretKey(inner, a_vec) + SecretKey(inner) } } @@ -242,9 +206,14 @@ impl Asym for Secp256k1 { impl PublicKeyTrait for PublicKey { type VecRepr = Vec; + type CompVecRepr = Vec; + + fn to_vec(&self) -> Self::VecRepr { + self.0.serialize()[1..PUB_SIZE + 1].to_vec() + } /// Should move to another trait. - fn to_compressed_vec(&self) -> Self::VecRepr { + fn to_compressed_vec(&self) -> Self::CompVecRepr { self.0.serialize_compressed().to_vec() } @@ -269,7 +238,11 @@ impl PublicKeyTrait for PublicKey { } impl SecretKeyTrait for SecretKey { - //type VecRepr = ClearOnDrop>; + type VecRepr = ClearOnDrop>; + + fn to_vec(&self) -> Self::VecRepr { + ClearOnDrop::new(self.0.serialize().to_vec()) + } fn sign(&self, message: &[u8]) -> Result, Error> { @@ -440,12 +413,3 @@ type AsymTest = Secp256k1; #[cfg(test)] ::tests_asym!(); -/// Default implementation is only for parity-ethereum secret-store -/// It would be good to remove it (there is a bit of refactoring). -/// Therefore the constraint is not explicit. -/// Please note that it is an invalid publickey. -impl Default for PublicKey { - fn default() -> Self { - NULL_PUB_K.clone() - } -} diff --git a/parity-crypto/src/traits/asym.rs b/parity-crypto/src/traits/asym.rs index c07a6c0a9..52d37a1c5 100644 --- a/parity-crypto/src/traits/asym.rs +++ b/parity-crypto/src/traits/asym.rs @@ -106,24 +106,32 @@ pub trait FiniteField: Asym { /// Contraint AsRef<[u8]>` is not memory efficient for ffi. /// Keeping in mind that the trait is here to make thing easier /// in a parity context. We assert that for use cases such as parity ethereum it is very usefull. -/// In the future a switch to having only a function returning `impl AsRef<[u8]>` -/// could be done but at the time it involves moving a huge amount of logic to this crate. -pub trait PublicKey: Sized + Eq + PartialEq + Clone + AsRef<[u8]> { +pub trait PublicKey: Sized + Eq + PartialEq + Clone { type VecRepr: AsRef<[u8]>; + type CompVecRepr: AsRef<[u8]>; + + /// return serialize key + fn to_vec(&self) -> Self::VecRepr; /// Should move to another trait. - fn to_compressed_vec(&self) -> Self::VecRepr; + fn to_compressed_vec(&self) -> Self::CompVecRepr; /// Compatibility, this should disappear, public key should always be valid. fn is_valid(&self) -> bool; fn verify(&self, signature: &[u8], message: &[u8]) -> Result; + } /// SecretKey (Private key). -pub trait SecretKey: Sized + Eq + PartialEq + Clone + AsRef<[u8]> { +pub trait SecretKey: Sized + Eq + PartialEq + Clone { + type VecRepr: AsRef<[u8]>; + + /// return serialize key + fn to_vec(&self) -> Self::VecRepr; + /// Sign a fix length message, returns a fix length signature fn sign(&self, message: &[u8]) -> Result, Error>; } @@ -183,7 +191,7 @@ mod tests { let pub2 = AsymTest::public_from_slice(&pk2[..]).unwrap(); AsymTest::public_add(&mut pub1, &pub2).unwrap(); - assert_eq!(&pub1.as_ref()[..], &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); + assert_eq!(AsRef::<[u8]>::as_ref(&pub1.to_vec()), &[101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 105, 186, 56, 102, 46, 147][..]); } #[test] @@ -194,7 +202,7 @@ mod tests { let sec = AsymTest::secret_from_slice(&sk[..]).unwrap(); AsymTest::public_mul(&mut pubk, &sec).unwrap(); - assert_eq!(&pubk.as_ref()[..], &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); + assert_eq!(AsRef::<[u8]>::as_ref(&pubk.to_vec()), &[98, 132, 11, 170, 93, 231, 41, 185, 180, 151, 185, 130, 77, 251, 41, 169, 160, 84, 133, 19, 82, 190, 137, 82, 0, 214, 148, 120, 165, 184, 17, 21, 237, 184, 119, 174, 13, 77, 50, 251, 16, 17, 197, 74, 232, 55, 142, 220, 27, 152, 4, 52, 69, 14, 76, 8, 156, 82, 0, 193, 179, 65, 63, 106][..]); } @@ -267,8 +275,8 @@ mod tests { let ck = [2, 126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115]; let pubk = AsymTest::public_from_slice(&pk[..]).unwrap(); let sec = AsymTest::secret_from_slice(&sk[..]).unwrap(); - assert!(pubk.as_ref() == &pk[..]); - assert!(sec.as_ref() == &sk[..]); + assert!(AsRef::<[u8]>::as_ref(&pubk.to_vec()) == &pk[..]); + assert!(AsRef::<[u8]>::as_ref(&sec.to_vec()) == &sk[..]); assert!(AsRef::<[u8]>::as_ref(&pubk.to_compressed_vec()) == &ck[..]); } } From 30d91988378d0f0c4c070c01620107e65334950a Mon Sep 17 00:00:00 2001 From: cheme Date: Thu, 15 Nov 2018 11:38:32 +0100 Subject: [PATCH 27/39] Do not allow invalid public keys. (remove default trait and test `is_valid`) And some tabify. --- mem/src/lib.rs | 4 ++-- parity-crypto/src/scrypt.rs | 32 +++++++++++++++--------------- parity-crypto/src/secp256k1.rs | 14 ------------- parity-crypto/src/secp256k1_alt.rs | 12 ++++------- parity-crypto/src/traits/asym.rs | 4 ---- 5 files changed, 22 insertions(+), 44 deletions(-) diff --git a/mem/src/lib.rs b/mem/src/lib.rs index edde14bfe..0ade536f3 100644 --- a/mem/src/lib.rs +++ b/mem/src/lib.rs @@ -26,7 +26,7 @@ pub use cod::clear::Clear; /// reexport clear_on_drop crate pub mod clear_on_drop { - pub use cod::*; + pub use cod::*; } /// Wrapper to zero out memory when dropped. @@ -55,7 +55,7 @@ impl> Drop for Memzero { #[cfg(not(feature = "volatile-erase"))] impl> Drop for Memzero { fn drop(&mut self) { - self.as_mut().clear(); + self.as_mut().clear(); } } diff --git a/parity-crypto/src/scrypt.rs b/parity-crypto/src/scrypt.rs index 7d9e83f9f..5b8bca37f 100644 --- a/parity-crypto/src/scrypt.rs +++ b/parity-crypto/src/scrypt.rs @@ -44,20 +44,20 @@ pub fn derive_key(pass: &[u8], salt: &[u8], n: u32, p: u32, r: u32) -> Result<(V // if previous crypto lib got a bug. #[test] pub fn test_derive() -> Result<(),Error> { - let pass = include_bytes!("../test/pass1"); - let salt_v = include_bytes!("../test/salt1"); - let mut salt = [0;32]; - salt.copy_from_slice(&salt_v[..32]); - let r1 = include_bytes!("../test/right1_1"); - let r2 = include_bytes!("../test/right1_2"); - let l1 = include_bytes!("../test/left1_1"); - let l2 = include_bytes!("../test/left1_2"); - - let (l,r) = derive_key(&pass[..],&salt, 262, 1, 8).unwrap(); - assert!(l == r1); - assert!(r == l1); - let (l,r) = derive_key(&pass[..],&salt, 144, 4, 4).unwrap(); - assert!(l == r2); - assert!(r == l2); - Ok(()) + let pass = include_bytes!("../test/pass1"); + let salt_v = include_bytes!("../test/salt1"); + let mut salt = [0;32]; + salt.copy_from_slice(&salt_v[..32]); + let r1 = include_bytes!("../test/right1_1"); + let r2 = include_bytes!("../test/right1_2"); + let l1 = include_bytes!("../test/left1_1"); + let l2 = include_bytes!("../test/left1_2"); + + let (l,r) = derive_key(&pass[..],&salt, 262, 1, 8).unwrap(); + assert!(l == r1); + assert!(r == l1); + let (l,r) = derive_key(&pass[..],&salt, 144, 4, 4).unwrap(); + assert!(l == r2); + assert!(r == l2); + Ok(()) } diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index ec5453922..a78d633e5 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -202,10 +202,6 @@ impl PublicKeyTrait for PublicKey { self.0.serialize_vec(&SECP256K1, true) } - fn is_valid(&self) -> bool { - self.0.is_valid() - } - fn verify(&self, signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; @@ -286,13 +282,3 @@ type AsymTest = Secp256k1; #[cfg(test)] ::tests_asym!(); - -/// Default implementation is only for parity-ethereum secret-store -/// It would be good to remove it (there is a bit of refactoring). -/// Therefore the constraint is not explicit. -/// Please note that it is an invalid publickey. -impl Default for PublicKey { - fn default() -> Self { - NULL_PUB_K.clone() - } -} diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index e70186853..1ff8c11d5 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -122,7 +122,10 @@ pub struct SecretKey(SecretKeyInner); impl Drop for SecretKey { fn drop(&mut self) { - // TODO find a way to clear secret + // TODO find a way to clear secret, next lines break on mem replace + //let key = std::mem::replace(&mut self.0, ZERO_KEY.0.clone()); + //let buf = &mut Into::::into(*key.inner).0; + //Clear::clear(buf); } } @@ -217,13 +220,6 @@ impl PublicKeyTrait for PublicKey { self.0.serialize_compressed().to_vec() } - fn is_valid(&self) -> bool { - // Check from other implementation only look for a non zero value in fields - // here we can - let aff: Affine = self.0.clone().into(); - aff.is_valid_var() - } - fn verify(&self, signature: &[u8], message: &[u8]) -> Result { let mut buf = [0;32]; buf.copy_from_slice(&message[..]); // panic on incorrect message size diff --git a/parity-crypto/src/traits/asym.rs b/parity-crypto/src/traits/asym.rs index 52d37a1c5..bccd77b2f 100644 --- a/parity-crypto/src/traits/asym.rs +++ b/parity-crypto/src/traits/asym.rs @@ -116,12 +116,8 @@ pub trait PublicKey: Sized + Eq + PartialEq + Clone { /// Should move to another trait. fn to_compressed_vec(&self) -> Self::CompVecRepr; - /// Compatibility, this should disappear, public key should always be valid. - fn is_valid(&self) -> bool; - fn verify(&self, signature: &[u8], message: &[u8]) -> Result; - } /// SecretKey (Private key). From c91370b9465161be0c24293ff55038e1572e2b16 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 20 Nov 2018 14:28:14 +0100 Subject: [PATCH 28/39] Avoid panicking on incorrect message/key length for secp256k1_alt --- parity-crypto/src/scrypt.rs | 4 ++-- parity-crypto/src/secp256k1_alt.rs | 34 ++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/parity-crypto/src/scrypt.rs b/parity-crypto/src/scrypt.rs index 5b8bca37f..65519962e 100644 --- a/parity-crypto/src/scrypt.rs +++ b/parity-crypto/src/scrypt.rs @@ -16,9 +16,9 @@ use error::ScryptError; use super::{KEY_LENGTH_AES, KEY_LENGTH}; -use rscrypt:: {scrypt, ScryptParams}; +use rscrypt::{scrypt, ScryptParams}; #[cfg(test)] -use std::io::{ Error }; +use std::io::Error; pub fn derive_key(pass: &[u8], salt: &[u8], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), ScryptError> { // sanity checks diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 1ff8c11d5..b7e75b964 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -153,10 +153,16 @@ impl Asym for Secp256k1 { fn recover(signature: &[u8], message: &[u8]) -> Result { let mut buf = [0;32]; - buf.copy_from_slice(&message[..]); // panic on incorrect message size + if message.len() != 32 { + return Err(InnerError::InvalidMessage.into()); + } + buf.copy_from_slice(&message[..]); let message = Message::parse(&buf); let mut buf = [0;64]; - buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size + if signature.len() < 65 { + return Err(InnerError::InvalidSignature.into()); + } + buf.copy_from_slice(&signature[..64]); let recovery_id = RecoveryId::parse(signature[64])?; let signature = Signature::parse(&buf); let public_key = secp256k1::recover(&message, &signature, &recovery_id)?; @@ -187,16 +193,21 @@ impl Asym for Secp256k1 { /// using a shortened 64bit public key as input fn public_from_slice(public_sec_raw: &[u8]) -> Result { - + if public_sec_raw.len() < PUB_SIZE { + return Err(InnerError::InvalidPublicKey.into()); + } let pdata = { let mut temp = [4u8; PUB_SIZE + 1]; - (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); + (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[..PUB_SIZE]); temp }; Ok(PublicKey::new(PublicKeyInner::parse(&pdata)?)) } fn secret_from_slice(secret: &[u8]) -> Result { + if secret.len() < SECRET_SIZE { + return Err(InnerError::InvalidSecretKey.into()); + } let mut buf = [0;32]; buf[..].copy_from_slice(&secret[..SECRET_SIZE]); let res = SecretKey::new(SecretKeyInner::parse(&buf)?); @@ -222,10 +233,16 @@ impl PublicKeyTrait for PublicKey { fn verify(&self, signature: &[u8], message: &[u8]) -> Result { let mut buf = [0;32]; - buf.copy_from_slice(&message[..]); // panic on incorrect message size + if message.len() != 32 { + return Err(InnerError::InvalidMessage.into()); + } + buf.copy_from_slice(&message[..]); let message = Message::parse(&buf); let mut buf = [0;64]; - buf.copy_from_slice(&signature[..64]); // panic on incorrect signature size + if signature.len() < 64 { + return Err(InnerError::InvalidSignature.into()); + } + buf.copy_from_slice(&signature[..64]); let signature = Signature::parse(&buf); Ok(secp256k1::verify(&message, &signature, &self.0)) @@ -243,7 +260,10 @@ impl SecretKeyTrait for SecretKey { fn sign(&self, message: &[u8]) -> Result, Error> { let mut buf = [0;32]; - buf.copy_from_slice(&message[..]); // panic on incorrect message size + if message.len() != 32 { + return Err(InnerError::InvalidMessage.into()); + } + buf.copy_from_slice(&message[..]); let message = Message::parse(&buf); let (sig, rec_id) = secp256k1::sign(&message, &self.0)?; let mut data_arr = vec![0; 65]; From 9968c7339c22552648bf10705e4e13b82e4cfd31 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 20 Nov 2018 15:00:36 +0100 Subject: [PATCH 29/39] No need for deprecated trait function. --- parity-crypto/Cargo.toml | 3 +-- parity-crypto/src/secp256k1.rs | 11 ---------- parity-crypto/src/secp256k1_alt.rs | 32 ------------------------------ parity-crypto/src/traits/asym.rs | 7 ------- 4 files changed, 1 insertion(+), 52 deletions(-) diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index e1066d496..baa2b966c 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -30,7 +30,6 @@ mem = { path = "../mem" } ring = "0.13" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } arrayvec = "0.4" # needed for eth-secp256k1 -rand = "0.4" hmac = { version = "0.7", optional = true } libsecp256k1 = { path = "./libsecp256k1", optional = true } pbkdf2 = { version = "0.3", default-features = false, optional = true } @@ -40,7 +39,6 @@ hmac = "0.7" subtle = { version = "1.0" } # libsecp256k1 = { version = "0.1", package = "libsecp256k1" } // requires 'rename-dependency' in stable libsecp256k1 = { path = "./libsecp256k1" } -rand = "0.5" pbkdf2 = { version = "0.3", default-features = false } [dev-dependencies] @@ -49,6 +47,7 @@ hmac = "0.7" libsecp256k1 = { path = "./libsecp256k1" } pbkdf2 = { version = "0.3", default-features = false } criterion = "0.2" +rand = "0.4" [features] # expose alternative wasm32 implementation for testing and benchmarks diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index a78d633e5..13e1bfd1d 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -21,12 +21,10 @@ extern crate secp256k1; extern crate arrayvec; -extern crate rand; use clear_on_drop::clear::Clear; use clear_on_drop::ClearOnDrop; use self::arrayvec::ArrayVec; -use self::rand::Rng; use super::traits::asym::{SecretKey as SecretKeyTrait, PublicKey as PublicKeyTrait, Asym, FiniteField, FixAsymSharedSecret}; use super::error::Error; @@ -115,15 +113,6 @@ impl Asym for Secp256k1 { Ok(PublicKey::new(pubkey)) } - - /// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. - /// The intent is to avoid depending on `Rng` trait. - fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey) { - let (s, p) = SECP256K1.generate_keypair(r) - .expect("context always created with full capabilities; qed"); - (SecretKey(s), PublicKey::new(p)) - } - /// create a key pair from byte value of the secret key, the calling function is responsible for /// erasing the input of memory. fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error> { diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index b7e75b964..ae3b157a2 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -17,9 +17,7 @@ //! secp256k1 for parity. extern crate libsecp256k1 as secp256k1; -extern crate rand; -use self::rand::Rng; use clear_on_drop::clear::Clear; use clear_on_drop::ClearOnDrop; use ::traits::asym::{ @@ -169,15 +167,6 @@ impl Asym for Secp256k1 { Ok(PublicKey::new(public_key)) } - - /// deprecated, we rather not expose Rng trait, use `keypair_from_slice` instead. - /// The intent is to avoid depending on `Rng` trait. - fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey) { - let secret_key = random_sec(r); - let public_key = PublicKeyInner::from_secret_key(&secret_key.0); - (secret_key, PublicKey::new(public_key)) - } - /// create a key pair from byte value of the secret key, the calling function is responsible for /// erasing the input of memory. fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error> { @@ -274,19 +263,6 @@ impl SecretKeyTrait for SecretKey { } -/// random secret key for rand 0.5 -fn random_sec(rng: &mut R) -> SecretKey { - loop { - let mut ret = [0u8; 32]; - rng.fill_bytes(&mut ret); - - match Secp256k1::secret_from_slice(&ret) { - Ok(key) => return key, - Err(_) => (), - } - } -} - impl FixAsymSharedSecret for SecretKey { type Other = PublicKey; type Result = SharedSecretAsRef; @@ -327,14 +303,6 @@ impl Drop for SecretScalar { } } -/* private inner method but this would avoid a scalar instantiation -fn mul_in_place_scalar(a: &mut Scalar, b: &Scalar) { - let mut l = [0u32; 16]; - a.mul_512(b, &mut l); - a.reduce_512(&l); -} -*/ - impl FiniteField for Secp256k1 { fn generator_x() -> &'static[u8] { &GENERATOR_X[..] } diff --git a/parity-crypto/src/traits/asym.rs b/parity-crypto/src/traits/asym.rs index bccd77b2f..998a997f1 100644 --- a/parity-crypto/src/traits/asym.rs +++ b/parity-crypto/src/traits/asym.rs @@ -16,10 +16,7 @@ //! asymetric trait -extern crate rand; - use ::error::Error; -use self::rand::Rng; /// Trait for asymetric crypto pub trait Asym { @@ -47,10 +44,6 @@ pub trait Asym { /// This function could move to a more specific trait in the future fn recover(signature: &[u8], message: &[u8]) -> Result; - /// Generate a key pair from a random function. - #[deprecated] - fn generate_keypair(r: &mut impl Rng) -> (Self::SecretKey, Self::PublicKey); - /// Generate a keypair from a random input fn keypair_from_slice(bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error>; From 0117a5f05c0711cbb76d6075ae6e017e29cc1348 Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 20 Nov 2018 17:45:18 +0100 Subject: [PATCH 30/39] Switch libsecp version. --- parity-crypto/libsecp256k1/Cargo.toml | 2 +- parity-crypto/src/secp256k1_alt.rs | 84 +++++---------------------- 2 files changed, 16 insertions(+), 70 deletions(-) diff --git a/parity-crypto/libsecp256k1/Cargo.toml b/parity-crypto/libsecp256k1/Cargo.toml index aeda5c9b6..a78212d42 100644 --- a/parity-crypto/libsecp256k1/Cargo.toml +++ b/parity-crypto/libsecp256k1/Cargo.toml @@ -7,4 +7,4 @@ description = "Renaming crate for libsecp256k1." license = "GPL-3.0" [dependencies] -libsecp256k1 = { version = "0.1" } +libsecp256k1 = { version = "0.2" } diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index ae3b157a2..142016e82 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -48,12 +48,8 @@ use self::secp256k1::{ use self::secp256k1::curve::{ Affine, Jacobian, - Scalar, }; -use self::secp256k1::curve::ECMULT_CONTEXT; - - const SIGN_SIZE: usize = 65; const PUB_SIZE: usize = 64; const SECRET_SIZE: usize = 32; @@ -120,10 +116,7 @@ pub struct SecretKey(SecretKeyInner); impl Drop for SecretKey { fn drop(&mut self) { - // TODO find a way to clear secret, next lines break on mem replace - //let key = std::mem::replace(&mut self.0, ZERO_KEY.0.clone()); - //let buf = &mut Into::::into(*key.inner).0; - //Clear::clear(buf); + Clear::clear(&mut self.0); } } @@ -150,19 +143,12 @@ impl Asym for Secp256k1 { const KEYPAIR_INPUT_SIZE: usize = Self::SECRET_SIZE; fn recover(signature: &[u8], message: &[u8]) -> Result { - let mut buf = [0;32]; - if message.len() != 32 { - return Err(InnerError::InvalidMessage.into()); - } - buf.copy_from_slice(&message[..]); - let message = Message::parse(&buf); - let mut buf = [0;64]; + let message = Message::parse_slice(&message[..])?; if signature.len() < 65 { return Err(InnerError::InvalidSignature.into()); } - buf.copy_from_slice(&signature[..64]); let recovery_id = RecoveryId::parse(signature[64])?; - let signature = Signature::parse(&buf); + let signature = Signature::parse_slice(&signature[..64])?; let public_key = secp256k1::recover(&message, &signature, &recovery_id)?; Ok(PublicKey::new(public_key)) } @@ -221,18 +207,11 @@ impl PublicKeyTrait for PublicKey { } fn verify(&self, signature: &[u8], message: &[u8]) -> Result { - let mut buf = [0;32]; - if message.len() != 32 { - return Err(InnerError::InvalidMessage.into()); - } - buf.copy_from_slice(&message[..]); - let message = Message::parse(&buf); - let mut buf = [0;64]; + let message = Message::parse_slice(&message[..])?; if signature.len() < 64 { return Err(InnerError::InvalidSignature.into()); } - buf.copy_from_slice(&signature[..64]); - let signature = Signature::parse(&buf); + let signature = Signature::parse_slice(&signature[..64])?; Ok(secp256k1::verify(&message, &signature, &self.0)) } @@ -247,13 +226,7 @@ impl SecretKeyTrait for SecretKey { } fn sign(&self, message: &[u8]) -> Result, Error> { - - let mut buf = [0;32]; - if message.len() != 32 { - return Err(InnerError::InvalidMessage.into()); - } - buf.copy_from_slice(&message[..]); - let message = Message::parse(&buf); + let message = Message::parse_slice(&message[..])?; let (sig, rec_id) = secp256k1::sign(&message, &self.0)?; let mut data_arr = vec![0; 65]; data_arr[0..64].copy_from_slice(&sig.serialize()); @@ -295,14 +268,6 @@ fn aff_to_public(aff_pub: &mut Affine) -> Result { Ok(PublicKeyInner::parse(&buff)?) } -struct SecretScalar(pub Scalar); - -impl Drop for SecretScalar { - fn drop(&mut self) { - self.0.clear(); - } -} - impl FiniteField for Secp256k1 { fn generator_x() -> &'static[u8] { &GENERATOR_X[..] } @@ -310,22 +275,14 @@ impl FiniteField for Secp256k1 { fn curve_order() -> &'static[u8] { &CURVE_ORDER[..] } fn public_mul(pub_key: &mut Self::PublicKey, sec_key: &Self::SecretKey) -> Result<(), Error> { - let sec_scal = SecretScalar(sec_key.0.clone().into()); - let mut pub_aff: Affine = pub_key.0.clone().into(); - let mut pub_jac = Jacobian::default(); - pub_jac.set_ge(&pub_aff); - //ECMULT_GEN_CONTEXT.ecmult_gen(&mut pub_jac, &sec_scal); - //pub_aff.set_gej(&pub_jac); - let mut zero = Scalar::default(); - zero.set_int(0); - let mut res = Jacobian::default(); - ECMULT_CONTEXT.ecmult(&mut res, &pub_jac, &sec_scal.0, &zero); - pub_aff.set_gej(&res); - *pub_key = PublicKey::new(aff_to_public(&mut pub_aff)?); + pub_key.0.tweak_mul_assign(&sec_key.0)?; Ok(()) } fn public_add(pub_key: &mut Self::PublicKey, other_public: &Self::PublicKey) -> Result<(), Error> { + // combine with iterator param would avoid some clone + // let keys = [other_public.0.clone(), pub_key.0.clone()]; + // *pub_key = PublicKey::new(PublicKeyInner::combine(&keys)?); let mut aff_pub: Affine = pub_key.0.clone().into(); let mut aff_pub_j = Jacobian::default(); aff_pub_j.set_ge(&aff_pub); @@ -338,30 +295,17 @@ impl FiniteField for Secp256k1 { } fn secret_mul(sec_key: &mut Self::SecretKey, other_sec_key: &Self::SecretKey) -> Result<(), Error> { - let sec_scal = SecretScalar(sec_key.0.clone().into()); - let other_sec_scal = SecretScalar(other_sec_key.0.clone().into()); - // we could use * operator instead. - let mut res = SecretScalar(Scalar::default()); - res.0.mul_in_place(&sec_scal.0, &other_sec_scal.0); - *sec_key = SecretKey::new(SecretKeyInner::parse(&res.0.b32())?); + sec_key.0.tweak_mul_assign(&other_sec_key.0)?; Ok(()) } fn secret_add(sec_key: &mut Self::SecretKey, other_sec_key: &Self::SecretKey) -> Result<(), Error> { - let sec_scal = SecretScalar(sec_key.0.clone().into()); - let other_sec_scal = SecretScalar(other_sec_key.0.clone().into()); - // we could use + operator instead. - let mut res = SecretScalar(Scalar::default()); - res.0.add_in_place(&sec_scal.0, &other_sec_scal.0); - *sec_key = SecretKey::new(SecretKeyInner::parse(&res.0.b32())?); + sec_key.0.tweak_add_assign(&other_sec_key.0)?; Ok(()) } fn secret_inv(sec_key: &mut Self::SecretKey) -> Result<(), Error> { - let sec_scal = SecretScalar(sec_key.0.clone().into()); - let mut res = SecretScalar(Scalar::default()); - res.0.inv_in_place(&sec_scal.0); - *sec_key = SecretKey::new(SecretKeyInner::parse(&res.0.b32())?); + *sec_key = SecretKey::new(sec_key.0.inv()); Ok(()) } @@ -387,6 +331,8 @@ impl From for Error { InnerError::InvalidPublicKey => Error::AsymShort("Invalid public"), InnerError::InvalidSignature => Error::AsymShort("Invalid EC signature"), InnerError::InvalidMessage => Error::AsymShort("Invalid AES message"), + InnerError::InvalidInputLength => Error::AsymShort("Invalid input Length"), + InnerError::TweakOutOfRange => Error::AsymShort("Tweak out of Range"), } } } From ac0eb938b6321a412b8ae4cf34d5efdab77aba8a Mon Sep 17 00:00:00 2001 From: cheme Date: Tue, 20 Nov 2018 22:11:42 +0100 Subject: [PATCH 31/39] Remove last maths from secp256k1_alt --- parity-crypto/src/secp256k1_alt.rs | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 142016e82..46daa0a5f 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -45,11 +45,6 @@ use self::secp256k1::{ RecoveryId, }; -use self::secp256k1::curve::{ - Affine, - Jacobian, -}; - const SIGN_SIZE: usize = 65; const PUB_SIZE: usize = 64; const SECRET_SIZE: usize = 32; @@ -256,18 +251,6 @@ impl AsRef<[u8]> for SharedSecretAsRef { } } -fn aff_to_public(aff_pub: &mut Affine) -> Result { - let mut buff = [4;65]; - let mut buff2 = [0;32]; - aff_pub.x.normalize(); - aff_pub.x.fill_b32(&mut buff2); - buff[1..33].copy_from_slice(&buff2[..]); - aff_pub.y.normalize(); - aff_pub.y.fill_b32(&mut buff2); - buff[33..65].copy_from_slice(&buff2[..]); - Ok(PublicKeyInner::parse(&buff)?) -} - impl FiniteField for Secp256k1 { fn generator_x() -> &'static[u8] { &GENERATOR_X[..] } @@ -280,17 +263,8 @@ impl FiniteField for Secp256k1 { } fn public_add(pub_key: &mut Self::PublicKey, other_public: &Self::PublicKey) -> Result<(), Error> { - // combine with iterator param would avoid some clone - // let keys = [other_public.0.clone(), pub_key.0.clone()]; - // *pub_key = PublicKey::new(PublicKeyInner::combine(&keys)?); - let mut aff_pub: Affine = pub_key.0.clone().into(); - let mut aff_pub_j = Jacobian::default(); - aff_pub_j.set_ge(&aff_pub); - let aff_pub_other: Affine = other_public.0.clone().into(); - let res_j = aff_pub_j.add_ge(&aff_pub_other); - aff_pub.set_gej(&res_j); - *pub_key = PublicKey::new(aff_to_public(&mut aff_pub)?); - + let keys = [other_public.0.clone(), pub_key.0.clone()]; + *pub_key = PublicKey::new(PublicKeyInner::combine(&keys)?); Ok(()) } From aa0bdca4ef23cd42980d57a6b8449066183b06e8 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 23 Nov 2018 14:23:09 +0100 Subject: [PATCH 32/39] Use rust-secp256k1 fork aligned to current master. --- mem/Cargo.toml | 7 ++- mem/README.md | 7 +++ mem/src/lib.rs | 2 + parity-crypto/Cargo.toml | 9 ++-- parity-crypto/benches/asym.rs | 3 ++ parity-crypto/src/aes.rs | 86 ++++++++++++++++-------------- parity-crypto/src/hmac_alt.rs | 2 +- parity-crypto/src/lib.rs | 2 +- parity-crypto/src/secp256k1.rs | 62 ++++++++++----------- parity-crypto/src/secp256k1_alt.rs | 6 +-- parity-crypto/src/traits/asym.rs | 5 +- 11 files changed, 102 insertions(+), 89 deletions(-) create mode 100644 mem/README.md diff --git a/mem/Cargo.toml b/mem/Cargo.toml index 343858b74..562d24748 100644 --- a/mem/Cargo.toml +++ b/mem/Cargo.toml @@ -1,10 +1,13 @@ [package] -name = "mem" +name = "parity-util-mem" version = "0.1.0" authors = ["Parity Technologies "] +repository = "https://github.com/paritytech/parity-common" +description = "Collection of memory related utilities" +license = "GPL-3.0" [dependencies] -clear_on_drop = "0.2.3" +clear_on_drop = "0.2" [features] # when activated mem is removed through volatile primitive instead of clear_on_drop crate diff --git a/mem/README.md b/mem/README.md new file mode 100644 index 000000000..80b1fd7ec --- /dev/null +++ b/mem/README.md @@ -0,0 +1,7 @@ +# parity-util-mem + +Collection of memory related utilities. + +## Features + +- volatile-erase : Not set by default, `Memzero` erase memory with `write_volatile`. diff --git a/mem/src/lib.rs b/mem/src/lib.rs index 0ade536f3..4d0e6fa23 100644 --- a/mem/src/lib.rs +++ b/mem/src/lib.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Memory related utilities. + extern crate clear_on_drop as cod; use std::ops::{Deref, DerefMut}; diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index baa2b966c..e982187e8 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -14,7 +14,6 @@ harness = false [dependencies] quick-error = "1.2.2" - tiny-keccak = "1.4" scrypt = { version = "0.1.1", default-features = false } ripemd160 = "0.8.0" @@ -24,12 +23,12 @@ aes = "0.3.2" aes-ctr = "0.3.0" block-modes = "0.2.0" lazy_static = "1.0" # for secp -mem = { path = "../mem" } +parity-util-mem = { version = "0.1", path = "../mem" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ring = "0.13" -eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } -arrayvec = "0.4" # needed for eth-secp256k1 +#secp256k1 = "0.11" +secp256k1 = { git = "https://github.com/cheme/rust-secp256k1", branch = "parity-eth" } hmac = { version = "0.7", optional = true } libsecp256k1 = { path = "./libsecp256k1", optional = true } pbkdf2 = { version = "0.3", default-features = false, optional = true } @@ -53,4 +52,4 @@ rand = "0.4" # expose alternative wasm32 implementation for testing and benchmarks alt = ["hmac", "libsecp256k1", "pbkdf2"] nightly = ["subtle/nightly"] -volatile-erase = ["mem/volatile-erase"] +volatile-erase = ["parity-util-mem/volatile-erase"] diff --git a/parity-crypto/benches/asym.rs b/parity-crypto/benches/asym.rs index 945f244d8..be3e45586 100644 --- a/parity-crypto/benches/asym.rs +++ b/parity-crypto/benches/asym.rs @@ -14,6 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . + +//! Benches related to asym crypto, mainly signing and veryfing. + use criterion::{Criterion, Bencher}; use parity_crypto::traits::asym::*; diff --git a/parity-crypto/src/aes.rs b/parity-crypto/src/aes.rs index 348801b6a..b83291bf5 100644 --- a/parity-crypto/src/aes.rs +++ b/parity-crypto/src/aes.rs @@ -36,7 +36,7 @@ impl AesEcb256 { Ok(AesEcb256(Ecb::new_varkey(key)?)) } - /// In place encrypt a content without padding, the content length must be a multiple + /// Encrypt data in place without padding. The data length must be a multiple /// of the block size. #[inline] pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { @@ -44,7 +44,7 @@ impl AesEcb256 { Ok(()) } - /// In place decrypt a content without padding, the content length must be a multiple + /// Decrypt data in place without padding. The data length must be a multiple /// of the block size. #[inline] pub fn decrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { @@ -88,7 +88,7 @@ impl AesCtr256 { /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. -/// If possible please use `inplace_encrypt_128_ctr` to avoid a slice copy. +/// If possible prefer `inplace_encrypt_128_ctr` to avoid a slice copy. pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { let mut encryptor = Aes128Ctr::new( GenericArray::from_slice(k), @@ -100,6 +100,9 @@ pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Re } +/// Encrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. pub fn inplace_encrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> { let mut encryptor = Aes128Ctr::new( @@ -115,7 +118,7 @@ pub fn inplace_encrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<( /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. -/// If possible please use `inplace_decrypt_128_ctr` instead. +/// If possible prefer `inplace_decrypt_128_ctr` instead. pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { let mut encryptor = Aes128Ctr::new( GenericArray::from_slice(k), @@ -142,15 +145,6 @@ pub fn inplace_decrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<( } -#[cfg(test)] -fn encrypt_128_cbc(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let encryptor = Cbc::::new_varkey(k, GenericArray::from_slice(iv))?; - &mut dest[..plain.len()].copy_from_slice(plain); - encryptor.encrypt_pad(dest, plain.len())?; - Ok(()) -} - - /// Decrypt a message (CBC mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. @@ -165,31 +159,43 @@ pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) - } -// retrocomptibility test -#[test] -pub fn test_aes_short() -> Result<(),SymmError> { - let key = include_bytes!("../test/key1"); - let salt = include_bytes!("../test/salt1"); - let content = include_bytes!("../test/content"); - let ctr_enc = include_bytes!("../test/result_128_ctr"); - let cbc_enc = include_bytes!("../test/result_128_cbc"); - let mut dest = vec![0;110]; - let mut dest_padded = vec![0;112]; - let mut dest_padded2 = vec![0;128]; // TODO RustLib need an extra 16bytes in dest : looks extra buggy but function is not currently use (keep it private for now) - encrypt_128_cbc(&key[..16], &salt[..16], content, &mut dest_padded2)?; - assert!(&dest_padded2[..112] == &cbc_enc[..]); - // buffer2.write_all(&dest1[..]).unwrap(); - encrypt_128_ctr(&key[..16], &salt[..16], content, &mut dest)?; - assert!(&dest[..] == &ctr_enc[..]); - let mut content_data = content.to_vec(); - inplace_encrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; - assert!(&content_data[..] == &ctr_enc[..]); - decrypt_128_ctr(&key[..16], &salt[..16], &ctr_enc[..], &mut dest)?; - assert!(&dest[..] == &content[..]); - let mut content_data = ctr_enc.to_vec(); - inplace_decrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; - assert!(&content_data[..] == &content[..]); - let l = decrypt_128_cbc(&key[..16], &salt[..16], &cbc_enc[..], &mut dest_padded)?; - assert!(&dest_padded[..l] == &content[..]); - Ok(()) +#[cfg(test)] +mod tests { + + use super::*; + + // only use for test could be expose in the future + fn encrypt_128_cbc(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let encryptor = Cbc::::new_varkey(k, GenericArray::from_slice(iv))?; + &mut dest[..plain.len()].copy_from_slice(plain); + encryptor.encrypt_pad(dest, plain.len())?; + Ok(()) + } + + #[test] + pub fn test_aes_short() -> Result<(),SymmError> { + let key = include_bytes!("../test/key1"); + let salt = include_bytes!("../test/salt1"); + let content = include_bytes!("../test/content"); + let ctr_enc = include_bytes!("../test/result_128_ctr"); + let cbc_enc = include_bytes!("../test/result_128_cbc"); + let mut dest = vec![0;110]; + let mut dest_padded = vec![0;112]; + let mut dest_padded2 = vec![0;128]; // TODO RustLib need an extra 16bytes in dest : looks extra buggy but function is not currently use (keep it private for now) + encrypt_128_cbc(&key[..16], &salt[..16], content, &mut dest_padded2)?; + assert!(&dest_padded2[..112] == &cbc_enc[..]); + encrypt_128_ctr(&key[..16], &salt[..16], content, &mut dest)?; + assert!(&dest[..] == &ctr_enc[..]); + let mut content_data = content.to_vec(); + inplace_encrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; + assert!(&content_data[..] == &ctr_enc[..]); + decrypt_128_ctr(&key[..16], &salt[..16], &ctr_enc[..], &mut dest)?; + assert!(&dest[..] == &content[..]); + let mut content_data = ctr_enc.to_vec(); + inplace_decrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; + assert!(&content_data[..] == &content[..]); + let l = decrypt_128_cbc(&key[..16], &salt[..16], &cbc_enc[..], &mut dest_padded)?; + assert!(&dest_padded[..l] == &content[..]); + Ok(()) + } } diff --git a/parity-crypto/src/hmac_alt.rs b/parity-crypto/src/hmac_alt.rs index 023a3bb32..05808cd34 100644 --- a/parity-crypto/src/hmac_alt.rs +++ b/parity-crypto/src/hmac_alt.rs @@ -21,7 +21,7 @@ use std::marker::PhantomData; use std::ops::Deref; use self::hmac::{Hmac, Mac}; -/// HMAC signature. Note the public interface of this module is a bit awkward for RustCrypto. +/// HMAC signature. Note the public interface of this module is not really fit for RustCrypto pub struct Signature(GenericArray, PhantomData); impl Deref for Signature { diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 5229d33a8..6cb444a82 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -32,7 +32,7 @@ extern crate digest as rdigest; extern crate aes as raes; extern crate aes_ctr; extern crate block_modes; -extern crate mem; +extern crate parity_util_mem as mem; /// reexport clear_on_drop crate pub mod clear_on_drop { diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index 13e1bfd1d..e0a036e70 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -20,11 +20,8 @@ //! highly inefficient here. extern crate secp256k1; -extern crate arrayvec; -use clear_on_drop::clear::Clear; -use clear_on_drop::ClearOnDrop; +use clear_on_drop::clear::{Clear, ClearOnDrop}; -use self::arrayvec::ArrayVec; use super::traits::asym::{SecretKey as SecretKeyTrait, PublicKey as PublicKeyTrait, Asym, FiniteField, FixAsymSharedSecret}; use super::error::Error; @@ -37,7 +34,7 @@ pub use self::secp256k1::{ pub use self::secp256k1::key::{SecretKey as SecretKeyInner, PublicKey as PublicKeyInner}; use self::secp256k1::constants::{SECRET_KEY_SIZE, GENERATOR_X, GENERATOR_Y, CURVE_ORDER}; -use self::secp256k1::key::{ZERO_KEY as ZERO_BYTES, ONE_KEY as ONE_BYTES, MINUS_ONE_KEY as MINUS_ONE_BYTES}; +use self::secp256k1::key::{ZERO_KEY as ZERO_BYTES, ONE_KEY as ONE_BYTES}; use self::secp256k1::{ Message, RecoverableSignature, @@ -45,12 +42,13 @@ use self::secp256k1::{ ecdh, }; +static MINUS_ONE_BYTES: [u8;32] = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 186, 174, 220, 230, 175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 64]; + lazy_static! { - pub static ref SECP256K1: self::secp256k1::Secp256k1 = self::secp256k1::Secp256k1::new(); - static ref MINUS_ONE_KEY: SecretKey = SecretKey(MINUS_ONE_BYTES); + pub static ref SECP256K1: self::secp256k1::Secp256k1 = self::secp256k1::Secp256k1::new(); + static ref MINUS_ONE_KEY: SecretKey = Secp256k1::secret_from_slice(&MINUS_ONE_BYTES[..]).expect("Init from valid const value; qed"); static ref ONE_KEY: SecretKey = SecretKey(ONE_BYTES); static ref ZERO_KEY: SecretKey = SecretKey(ZERO_BYTES); - static ref NULL_PUB_K: PublicKey = PublicKey::unsafe_empty(); } #[derive(PartialEq, Eq, Debug, Clone)] @@ -64,6 +62,7 @@ impl AsRef<[u8]> for SharedSecretAsRef { const SIGN_SIZE: usize = 65; const PUB_SIZE: usize = 64; +const COMPRESSED_PUB_SIZE: usize = 33; // not vec size could be reduce to 64 (higher instantiation cost) #[derive(PartialEq, Eq, Debug, Clone)] @@ -75,9 +74,6 @@ impl PublicKey { PublicKey(inner) } - fn unsafe_empty() -> Self { - PublicKey(PublicKeyInner::new()) - } } #[derive(PartialEq, Eq, Debug, Clone)] @@ -108,7 +104,7 @@ impl Asym for Secp256k1 { fn recover(signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; + let rsig = RecoverableSignature::from_compact(&signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; let pubkey = context.recover(&Message::from_slice(message)?, &rsig)?; Ok(PublicKey::new(pubkey)) } @@ -117,14 +113,14 @@ impl Asym for Secp256k1 { /// erasing the input of memory. fn keypair_from_slice(sk_bytes: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), Error> { assert!(sk_bytes.len() == SECRET_KEY_SIZE); - let sk = SecretKeyInner::from_slice(&SECP256K1, sk_bytes)?; + let sk = SecretKeyInner::from_slice(sk_bytes)?; let sc = SecretKey(sk); - let pk = PublicKeyInner::from_secret_key(&SECP256K1, &sc.0)?; + let pk = PublicKeyInner::from_secret_key(&SECP256K1, &sc.0); Ok((sc, PublicKey::new(pk))) } fn public_from_secret(s: &Self::SecretKey) -> Result { - Ok(PublicKey::new(PublicKeyInner::from_secret_key(&SECP256K1, &s.0)?)) + Ok(PublicKey::new(PublicKeyInner::from_secret_key(&SECP256K1, &s.0))) } /// using a shortened 64bit public key as input @@ -134,11 +130,11 @@ impl Asym for Secp256k1 { (&mut temp[1..PUB_SIZE + 1]).copy_from_slice(&public_sec_raw[0..PUB_SIZE]); temp }; - Ok(PublicKey::new(PublicKeyInner::from_slice(&SECP256K1, &pdata)?)) + Ok(PublicKey::new(PublicKeyInner::from_slice(&pdata)?)) } fn secret_from_slice(secret: &[u8]) -> Result { - Ok(SecretKey(SecretKeyInner::from_slice(&SECP256K1, secret)?)) + Ok(SecretKey(SecretKeyInner::from_slice(secret)?)) } } @@ -148,7 +144,7 @@ impl FixAsymSharedSecret for SecretKey { type Result = SharedSecretAsRef; fn shared_secret(&self, publ: &Self::Other) -> Result { - let shared = ecdh::SharedSecret::new_raw(&SECP256K1, &publ.0, &self.0); + let shared = ecdh::SharedSecret::new_raw(&publ.0, &self.0); Ok(SharedSecretAsRef(shared)) } @@ -159,8 +155,8 @@ impl SecretKeyTrait for SecretKey { fn sign(&self, message: &[u8]) -> Result, Error> { let context = &SECP256K1; - let s = context.sign_recoverable(&Message::from_slice(message)?, &self.0)?; - let (rec_id, data) = s.serialize_compact(context); + let s = context.sign_recoverable(&Message::from_slice(message)?, &self.0); + let (rec_id, data) = s.serialize_compact(); let mut data_arr = vec![0; SIGN_SIZE]; // no need to check if s is low, it always is @@ -176,25 +172,23 @@ impl SecretKeyTrait for SecretKey { } impl PublicKeyTrait for PublicKey { - type VecRepr = ArrayVec<[u8; 72]>; - type CompVecRepr = ArrayVec<[u8; 72]>; + const COMPRESSED_PUB_SIZE: usize = COMPRESSED_PUB_SIZE; + type VecRepr = Vec; + type CompVecRepr = Vec; fn to_vec(&self) -> Self::VecRepr { - let mut a_vec = self.0.serialize_vec(&SECP256K1, false); - let _ = a_vec.drain(PUB_SIZE + 1..); - a_vec.remove(0); - a_vec + self.0.serialize_uncompressed()[1..PUB_SIZE + 1].to_vec() } /// Should move to another trait. fn to_compressed_vec(&self) -> Self::CompVecRepr { - self.0.serialize_vec(&SECP256K1, true) + self.0.serialize().to_vec() } fn verify(&self, signature: &[u8], message: &[u8]) -> Result { let context = &SECP256K1; - let rsig = RecoverableSignature::from_compact(context, &signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; - let sig = rsig.to_standard(context); + let rsig = RecoverableSignature::from_compact(&signature[0..PUB_SIZE], RecoveryId::from_i32(signature[PUB_SIZE] as i32)?)?; + let sig = rsig.to_standard(); match context.verify(&Message::from_slice(message)?, &sig, &self.0) { Ok(_) => Ok(true), @@ -219,22 +213,23 @@ impl FiniteField for Secp256k1 { } fn public_add(pub_key: &mut Self::PublicKey, other_public: &Self::PublicKey) -> Result<(), Error> { - pub_key.0.add_assign(&SECP256K1, &other_public.0)?; + let res = other_public.0.combine(&pub_key.0)?; + *pub_key = PublicKey::new(res); Ok(()) } fn secret_mul(sec_key: &mut Self::SecretKey, other_secret: &Self::SecretKey) -> Result<(), Error> { - sec_key.0.mul_assign(&SECP256K1, &other_secret.0)?; + sec_key.0.mul_assign(&other_secret.0)?; Ok(()) } fn secret_add(sec_key: &mut Self::SecretKey, other_secret: &Self::SecretKey) -> Result<(), Error> { - sec_key.0.add_assign(&SECP256K1, &other_secret.0)?; + sec_key.0.add_assign(&other_secret.0)?; Ok(()) } fn secret_inv(sec_key: &mut Self::SecretKey) -> Result<(), Error> { - sec_key.0.inv_assign(&SECP256K1)?; + sec_key.0.inv_assign()?; Ok(()) } @@ -261,7 +256,6 @@ impl From for Error { InnerError::InvalidSignature | InnerError::IncorrectSignature => Error::AsymShort("Invalid EC signature"), InnerError::InvalidMessage => Error::AsymShort("Invalid AES message"), - _ => Error::AsymFull(Box::new(err)) } } } diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 46daa0a5f..737a21b97 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -47,6 +47,7 @@ use self::secp256k1::{ const SIGN_SIZE: usize = 65; const PUB_SIZE: usize = 64; +const COMPRESSED_PUB_SIZE: usize = 33; const SECRET_SIZE: usize = 32; const MINUS_ONE_BYTES: [u8;32] = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 186, 174, 220, 230, 175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 64]; @@ -99,11 +100,9 @@ pub fn minus_one_key() -> &'static SecretKey { pub struct PublicKey(PublicKeyInner); impl PublicKey { - fn new(inner: PublicKeyInner) -> Self { PublicKey(inner) } - } #[derive(PartialEq, Eq, Debug, Clone)] @@ -116,11 +115,9 @@ impl Drop for SecretKey { } impl SecretKey { - fn new(inner: SecretKeyInner) -> Self { SecretKey(inner) } - } impl Asym for Secp256k1 { @@ -189,6 +186,7 @@ impl Asym for Secp256k1 { } impl PublicKeyTrait for PublicKey { + const COMPRESSED_PUB_SIZE: usize = COMPRESSED_PUB_SIZE; type VecRepr = Vec; type CompVecRepr = Vec; diff --git a/parity-crypto/src/traits/asym.rs b/parity-crypto/src/traits/asym.rs index 998a997f1..80ce03a17 100644 --- a/parity-crypto/src/traits/asym.rs +++ b/parity-crypto/src/traits/asym.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! asymetric trait +//! Asymetric crypto traits. use ::error::Error; -/// Trait for asymetric crypto +/// Trait for asymetric crypto. pub trait Asym { /// Signature expected size in bytes @@ -100,6 +100,7 @@ pub trait FiniteField: Asym { /// Keeping in mind that the trait is here to make thing easier /// in a parity context. We assert that for use cases such as parity ethereum it is very usefull. pub trait PublicKey: Sized + Eq + PartialEq + Clone { + const COMPRESSED_PUB_SIZE: usize; type VecRepr: AsRef<[u8]>; type CompVecRepr: AsRef<[u8]>; From ed370ccd65ce89a2ba1e9ef4437481de576f3831 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 23 Nov 2018 15:07:07 +0100 Subject: [PATCH 33/39] Fix import, remove inlines. --- parity-crypto/src/aes.rs | 6 ------ parity-crypto/src/secp256k1.rs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/parity-crypto/src/aes.rs b/parity-crypto/src/aes.rs index b83291bf5..a9242f17d 100644 --- a/parity-crypto/src/aes.rs +++ b/parity-crypto/src/aes.rs @@ -31,14 +31,12 @@ pub struct AesEcb256(Ecb); impl AesEcb256 { /// New encoder/decoder, no iv for ecb - #[inline] pub fn new(key: &[u8]) -> Result { Ok(AesEcb256(Ecb::new_varkey(key)?)) } /// Encrypt data in place without padding. The data length must be a multiple /// of the block size. - #[inline] pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { self.0.encrypt_nopad(content)?; Ok(()) @@ -46,7 +44,6 @@ impl AesEcb256 { /// Decrypt data in place without padding. The data length must be a multiple /// of the block size. - #[inline] pub fn decrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { self.0.decrypt_nopad(content)?; Ok(()) @@ -60,7 +57,6 @@ pub struct AesCtr256(Aes256Ctr); impl AesCtr256 { /// New encoder/decoder - #[inline] pub fn new(key: &[u8], iv: &[u8]) -> Result { Ok(AesCtr256( Aes256Ctr::new(GenericArray::from_slice(key), GenericArray::from_slice(iv)) @@ -69,7 +65,6 @@ impl AesCtr256 { /// In place encrypt a content without padding, the content length must be a multiple /// of the block size. - #[inline] pub fn encrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { self.0.try_apply_keystream(content)?; Ok(()) @@ -77,7 +72,6 @@ impl AesCtr256 { /// In place decrypt a content without padding, the content length must be a multiple /// of the block size. - #[inline] pub fn decrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { self.0.try_apply_keystream(content)?; Ok(()) diff --git a/parity-crypto/src/secp256k1.rs b/parity-crypto/src/secp256k1.rs index e0a036e70..cb0fc933c 100644 --- a/parity-crypto/src/secp256k1.rs +++ b/parity-crypto/src/secp256k1.rs @@ -20,7 +20,7 @@ //! highly inefficient here. extern crate secp256k1; -use clear_on_drop::clear::{Clear, ClearOnDrop}; +use clear_on_drop::{clear::Clear, ClearOnDrop}; use super::traits::asym::{SecretKey as SecretKeyTrait, PublicKey as PublicKeyTrait, Asym, FiniteField, FixAsymSharedSecret}; From 6a6a111e8b30963ade11b6c53c4c2d546424cc05 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 30 Nov 2018 12:06:30 +0100 Subject: [PATCH 34/39] Switch to RustCrypto. --- Cargo.toml | 2 +- parity-crypto/Cargo.toml | 19 +++- parity-crypto/benches/bench.rs | 56 ++++++++++ parity-crypto/src/aes.rs | 168 +++++++++++++++++++++++++++--- parity-crypto/src/digest.rs | 58 +++++++---- parity-crypto/src/error.rs | 64 ++++++++++-- parity-crypto/src/hmac.rs | 48 +++++++++ parity-crypto/src/lib.rs | 8 +- parity-crypto/src/pbkdf2.rs | 25 +++++ parity-crypto/src/scrypt.rs | 31 +++++- parity-crypto/test/content | 2 + parity-crypto/test/key1 | 1 + parity-crypto/test/left1_1 | 1 + parity-crypto/test/left1_2 | 1 + parity-crypto/test/pass1 | 1 + parity-crypto/test/result_128_cbc | Bin 0 -> 112 bytes parity-crypto/test/result_128_ctr | 3 + parity-crypto/test/right1_1 | 1 + parity-crypto/test/right1_2 | 1 + parity-crypto/test/salt1 | 1 + 20 files changed, 442 insertions(+), 49 deletions(-) create mode 100644 parity-crypto/benches/bench.rs create mode 100644 parity-crypto/test/content create mode 100644 parity-crypto/test/key1 create mode 100644 parity-crypto/test/left1_1 create mode 100644 parity-crypto/test/left1_2 create mode 100644 parity-crypto/test/pass1 create mode 100644 parity-crypto/test/result_128_cbc create mode 100644 parity-crypto/test/result_128_ctr create mode 100644 parity-crypto/test/right1_1 create mode 100644 parity-crypto/test/right1_2 create mode 100644 parity-crypto/test/salt1 diff --git a/Cargo.toml b/Cargo.toml index a8796ce87..0d6dbe4c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,5 @@ members = [ "trace-time", "trie-standardmap", "triehash", - "uint" + "uint", ] diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index af6f35a27..d444c58c9 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -5,9 +5,24 @@ authors = ["Parity Technologies "] repository = "https://github.com/paritytech/parity-common" description = "Crypto utils used by ethstore and network." license = "GPL-3.0" +autobenches = false + +[[bench]] +name = "bench" +harness = false + [dependencies] quick-error = "1.2.2" -ring = "0.13" -rust-crypto = "0.2.36" tiny-keccak = "1.4" +scrypt = { version = "0.1.1", default-features = false } +ripemd160 = "0.8.0" +sha2 = "0.8.0" +digest = "0.8" +aes = "0.3.2" +aes-ctr = "0.3.0" +block-modes = "0.2.0" +ring = "0.13" + +[dev-dependencies] +criterion = "0.2" diff --git a/parity-crypto/benches/bench.rs b/parity-crypto/benches/bench.rs new file mode 100644 index 000000000..f9f68dfd1 --- /dev/null +++ b/parity-crypto/benches/bench.rs @@ -0,0 +1,56 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +extern crate parity_crypto; + +#[macro_use] +extern crate criterion; + +use criterion::{Criterion, Bencher}; + +criterion_group!(benches, input_len); + +criterion_main!(benches); + +/// general benches for multiple input size +fn input_len(c: &mut Criterion) { + + c.bench_function_over_inputs("ripemd", + |b: &mut Bencher, size: &usize| { + let data = vec![0u8; *size]; + b.iter(|| parity_crypto::digest::ripemd160(&data[..])); + }, + vec![100, 500, 1_000, 10_000, 100_000] + ); + + c.bench_function_over_inputs("aes_ctr", + |b: &mut Bencher, size: &usize| { + let data = vec![0u8; *size]; + let mut dest = vec![0; *size]; + let k = [0; 16]; + let iv = [0; 16]; + + b.iter(||{ + parity_crypto::aes::encrypt_128_ctr(&k[..], &iv[..], &data[..], &mut dest[..]).unwrap(); + // same as encrypt but add it just in case + parity_crypto::aes::decrypt_128_ctr(&k[..], &iv[..], &data[..], &mut dest[..]).unwrap(); + }); + }, + vec![100, 500, 1_000, 10_000, 100_000] + ); + +} diff --git a/parity-crypto/src/aes.rs b/parity-crypto/src/aes.rs index 42a26fad0..a9242f17d 100644 --- a/parity-crypto/src/aes.rs +++ b/parity-crypto/src/aes.rs @@ -14,40 +14,182 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use block_modes::{ BlockMode, BlockModeIv }; +use block_modes::block_padding::Pkcs7; +use block_modes::block_padding::ZeroPadding; +use block_modes::{ Cbc, Ecb }; +use raes::{ Aes128, Aes256 }; +use aes_ctr::{ Aes128Ctr, Aes256Ctr }; +use aes_ctr::stream_cipher::{ NewStreamCipher, SyncStreamCipher }; use error::SymmError; -use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; -use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; -use rcrypto::symmetriccipher::{Encryptor, Decryptor}; -use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer}; +use raes::block_cipher_trait::generic_array::GenericArray; + + +/// Reusable encoder/decoder for Ecb mode Aes256 with zero padding +pub struct AesEcb256(Ecb); + +impl AesEcb256 { + + /// New encoder/decoder, no iv for ecb + pub fn new(key: &[u8]) -> Result { + Ok(AesEcb256(Ecb::new_varkey(key)?)) + } + + /// Encrypt data in place without padding. The data length must be a multiple + /// of the block size. + pub fn encrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { + self.0.encrypt_nopad(content)?; + Ok(()) + } + + /// Decrypt data in place without padding. The data length must be a multiple + /// of the block size. + pub fn decrypt(&mut self, content: &mut [u8]) -> Result<(), SymmError> { + self.0.decrypt_nopad(content)?; + Ok(()) + } +} + + +/// Reusable encoder/decoder for Aes256 in Ctr mode and no padding +pub struct AesCtr256(Aes256Ctr); + +impl AesCtr256 { + + /// New encoder/decoder + pub fn new(key: &[u8], iv: &[u8]) -> Result { + Ok(AesCtr256( + Aes256Ctr::new(GenericArray::from_slice(key), GenericArray::from_slice(iv)) + )) + } + + /// In place encrypt a content without padding, the content length must be a multiple + /// of the block size. + pub fn encrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { + self.0.try_apply_keystream(content)?; + Ok(()) + } + + /// In place decrypt a content without padding, the content length must be a multiple + /// of the block size. + pub fn decrypt(&mut self, content: &mut[u8]) -> Result<(), SymmError> { + self.0.try_apply_keystream(content)?; + Ok(()) + } +} /// Encrypt a message (CTR mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. +/// If possible prefer `inplace_encrypt_128_ctr` to avoid a slice copy. pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?; + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + &mut dest[..plain.len()].copy_from_slice(plain); + encryptor.try_apply_keystream(dest)?; Ok(()) + +} + +/// Encrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn inplace_encrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + encryptor.try_apply_keystream(data)?; + Ok(()) + } /// Decrypt a message (CTR mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. +/// If possible prefer `inplace_decrypt_128_ctr` instead. pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { - let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?; + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + + &mut dest[..encrypted.len()].copy_from_slice(encrypted); + encryptor.try_apply_keystream(dest)?; Ok(()) } +/// Decrypt a message (CTR mode). +/// +/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. +/// An error is returned if the input lengths are invalid. +pub fn inplace_decrypt_128_ctr(k: &[u8], iv: &[u8], data: &mut [u8]) -> Result<(), SymmError> { + let mut encryptor = Aes128Ctr::new( + GenericArray::from_slice(k), + GenericArray::from_slice(iv), + ); + + encryptor.try_apply_keystream(data)?; + Ok(()) +} + + /// Decrypt a message (CBC mode). /// /// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each. /// An error is returned if the input lengths are invalid. pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result { - let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); - let len = dest.len(); - let mut buffer = RefWriteBuffer::new(dest); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?; - Ok(len - buffer.remaining()) + let encryptor = Cbc::::new_varkey(k, GenericArray::from_slice(iv))?; + &mut dest[..encrypted.len()].copy_from_slice(encrypted); + let unpad_length = { + encryptor.decrypt_pad(&mut dest[..encrypted.len()])?.len() + }; + Ok(unpad_length) +} + + +#[cfg(test)] +mod tests { + + use super::*; + + // only use for test could be expose in the future + fn encrypt_128_cbc(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> { + let encryptor = Cbc::::new_varkey(k, GenericArray::from_slice(iv))?; + &mut dest[..plain.len()].copy_from_slice(plain); + encryptor.encrypt_pad(dest, plain.len())?; + Ok(()) + } + + #[test] + pub fn test_aes_short() -> Result<(),SymmError> { + let key = include_bytes!("../test/key1"); + let salt = include_bytes!("../test/salt1"); + let content = include_bytes!("../test/content"); + let ctr_enc = include_bytes!("../test/result_128_ctr"); + let cbc_enc = include_bytes!("../test/result_128_cbc"); + let mut dest = vec![0;110]; + let mut dest_padded = vec![0;112]; + let mut dest_padded2 = vec![0;128]; // TODO RustLib need an extra 16bytes in dest : looks extra buggy but function is not currently use (keep it private for now) + encrypt_128_cbc(&key[..16], &salt[..16], content, &mut dest_padded2)?; + assert!(&dest_padded2[..112] == &cbc_enc[..]); + encrypt_128_ctr(&key[..16], &salt[..16], content, &mut dest)?; + assert!(&dest[..] == &ctr_enc[..]); + let mut content_data = content.to_vec(); + inplace_encrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; + assert!(&content_data[..] == &ctr_enc[..]); + decrypt_128_ctr(&key[..16], &salt[..16], &ctr_enc[..], &mut dest)?; + assert!(&dest[..] == &content[..]); + let mut content_data = ctr_enc.to_vec(); + inplace_decrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; + assert!(&content_data[..] == &content[..]); + let l = decrypt_128_cbc(&key[..16], &salt[..16], &cbc_enc[..], &mut dest_padded)?; + assert!(&dest_padded[..l] == &content[..]); + Ok(()) + } } diff --git a/parity-crypto/src/digest.rs b/parity-crypto/src/digest.rs index b2be0b8ed..40bafe145 100644 --- a/parity-crypto/src/digest.rs +++ b/parity-crypto/src/digest.rs @@ -14,37 +14,46 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use rcrypto::ripemd160; -use ring::digest::{self, Context, SHA256, SHA512}; +use rripemd160; +use rsha2; use std::marker::PhantomData; use std::ops::Deref; +use rdigest::generic_array::GenericArray; +use rdigest::generic_array::typenum::{U20, U32, U64}; +use rsha2::Digest as RDigest; /// The message digest. pub struct Digest(InnerDigest, PhantomData); enum InnerDigest { - Ring(digest::Digest), - Ripemd160([u8; 20]), + Sha256(GenericArray), + Sha512(GenericArray), + Ripemd160(GenericArray), } impl Deref for Digest { type Target = [u8]; fn deref(&self) -> &Self::Target { match self.0 { - InnerDigest::Ring(ref d) => d.as_ref(), - InnerDigest::Ripemd160(ref d) => &d[..] + InnerDigest::Sha256(ref d) => &d[..], + InnerDigest::Sha512(ref d) => &d[..], + InnerDigest::Ripemd160(ref d) => &d[..], } } } /// Single-step sha256 digest computation. pub fn sha256(data: &[u8]) -> Digest { - Digest(InnerDigest::Ring(digest::digest(&SHA256, data)), PhantomData) + let mut hasher = Hasher::sha256(); + hasher.update(data); + hasher.finish() } /// Single-step sha512 digest computation. pub fn sha512(data: &[u8]) -> Digest { - Digest(InnerDigest::Ring(digest::digest(&SHA512, data)), PhantomData) + let mut hasher = Hasher::sha512(); + hasher.update(data); + hasher.finish() } /// Single-step ripemd160 digest computation. @@ -62,34 +71,39 @@ pub enum Ripemd160 {} pub struct Hasher(Inner, PhantomData); enum Inner { - Ring(Context), - Ripemd160(ripemd160::Ripemd160) + Sha256(rsha2::Sha256), + Sha512(rsha2::Sha512), + Ripemd160(rripemd160::Ripemd160) } impl Hasher { pub fn sha256() -> Hasher { - Hasher(Inner::Ring(Context::new(&SHA256)), PhantomData) + Hasher(Inner::Sha256(rsha2::Sha256::default()), PhantomData) } } impl Hasher { pub fn sha512() -> Hasher { - Hasher(Inner::Ring(Context::new(&SHA512)), PhantomData) + Hasher(Inner::Sha512(rsha2::Sha512::default()), PhantomData) } } impl Hasher { pub fn ripemd160() -> Hasher { - Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData) + Hasher(Inner::Ripemd160(rripemd160::Ripemd160::default()), PhantomData) } } impl Hasher { pub fn update(&mut self, data: &[u8]) { match self.0 { - Inner::Ring(ref mut ctx) => ctx.update(data), + Inner::Sha256(ref mut ctx) => { + ctx.input(data) + }, + Inner::Sha512(ref mut ctx) => { + ctx.input(data) + }, Inner::Ripemd160(ref mut ctx) => { - use rcrypto::digest::Digest; ctx.input(data) } } @@ -97,12 +111,14 @@ impl Hasher { pub fn finish(self) -> Digest { match self.0 { - Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData), - Inner::Ripemd160(mut ctx) => { - use rcrypto::digest::Digest; - let mut d = [0; 20]; - ctx.result(&mut d); - Digest(InnerDigest::Ripemd160(d), PhantomData) + Inner::Sha256(ctx) => { + Digest(InnerDigest::Sha256(ctx.result()), PhantomData) + }, + Inner::Sha512(ctx) => { + Digest(InnerDigest::Sha512(ctx.result()), PhantomData) + }, + Inner::Ripemd160(ctx) => { + Digest(InnerDigest::Ripemd160(ctx.result()), PhantomData) } } } diff --git a/parity-crypto/src/error.rs b/parity-crypto/src/error.rs index 4e5582e19..64ffabcfb 100644 --- a/parity-crypto/src/error.rs +++ b/parity-crypto/src/error.rs @@ -14,8 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use rcrypto; use ring; +use rscrypt; +use block_modes; +use raes; +use aes_ctr; +use std::error::Error as StdError; quick_error! { #[derive(Debug)] @@ -28,6 +32,19 @@ quick_error! { cause(e) from() } + AsymShort(det: &'static str) { + description(det) + } + AsymFull(e: Box) { + cause(&**e) + description(e.description()) + } + } +} + +impl Into for Error { + fn into(self) -> std::io::Error { + std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self)) } } @@ -42,24 +59,43 @@ quick_error! { InvalidP { display("Invalid p argument of the scrypt encryption") } + ScryptParam(e: rscrypt::errors::InvalidParams) { + display("invalid params for scrypt: {}", e) + cause(e) + from() + } + ScryptLength(e: rscrypt::errors::InvalidOutputLen) { + display("invalid scrypt output length: {}", e) + cause(e) + from() + } } } + quick_error! { #[derive(Debug)] pub enum SymmError wraps PrivSymmErr { - RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) { + Offset(x: usize) { + display("offset {} greater than slice length", x) + } + BlockMode(e: block_modes::BlockModeError) { display("symmetric crypto error") from() } + KeyStream(e: aes_ctr::stream_cipher::LoopError) { + display("ctr key stream ended") + from() + } + InvalidKeyLength(e: raes::block_cipher_trait::InvalidKeyLength) { + display("Error with RustCrypto key length : {}", e) + from() + } Ring(e: ring::error::Unspecified) { display("symmetric crypto error") cause(e) from() } - Offset(x: usize) { - display("offset {} greater than slice length", x) - } } } @@ -75,8 +111,20 @@ impl From for SymmError { } } -impl From for SymmError { - fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError { - SymmError(PrivSymmErr::RustCrypto(e)) +impl From for SymmError { + fn from(e: block_modes::BlockModeError) -> SymmError { + SymmError(PrivSymmErr::BlockMode(e)) + } +} + +impl From for SymmError { + fn from(e: raes::block_cipher_trait::InvalidKeyLength) -> SymmError { + SymmError(PrivSymmErr::InvalidKeyLength(e)) + } +} + +impl From for SymmError { + fn from(e: aes_ctr::stream_cipher::LoopError) -> SymmError { + SymmError(PrivSymmErr::KeyStream(e)) } } diff --git a/parity-crypto/src/hmac.rs b/parity-crypto/src/hmac.rs index ff337ed02..0526367a4 100644 --- a/parity-crypto/src/hmac.rs +++ b/parity-crypto/src/hmac.rs @@ -86,3 +86,51 @@ impl VerifyKey { pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { hmac::verify(&k.0, data, sig).is_ok() } + + +#[cfg(test)] +::tests_hmac!(); + +#[cfg(test)] +#[macro_export] +macro_rules! tests_hmac { + () => { + +pub mod test { + use super::*; + #[test] + fn simple_mac_and_verify() { + let input = b"Some bytes"; + let big_input = vec![7u8;2000]; + + let key1 = vec![3u8;64]; + let key2 = vec![4u8;128]; + + let sig_key1 = SigKey::sha256(&key1[..]); + let sig_key2 = SigKey::sha512(&key2[..]); + + let mut signer1 = Signer::with(&sig_key1); + let mut signer2 = Signer::with(&sig_key2); + + signer1.update(&input[..]); + for i in 0 .. big_input.len() / 33 { + signer2.update(&big_input[i*33..(i+1)*33]); + } + signer2.update(&big_input[(big_input.len() / 33)*33..]); + let sig1 = signer1.sign(); + assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); + let sig2 = signer2.sign(); + assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); + assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); + assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); + let verif_key1 = VerifyKey::sha256(&key1[..]); + let verif_key2 = VerifyKey::sha512(&key2[..]); + assert!(verify(&verif_key1, &input[..], &sig1[..])); + assert!(verify(&verif_key2, &big_input[..], &sig2[..])); + + } +} + +} +} + diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 2785bc85b..d23241e5b 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -16,11 +16,17 @@ //! Crypto utils used by ethstore and network. -extern crate crypto as rcrypto; #[macro_use] extern crate quick_error; extern crate ring; extern crate tiny_keccak; +extern crate scrypt as rscrypt; +extern crate ripemd160 as rripemd160; +extern crate sha2 as rsha2; +extern crate digest as rdigest; +extern crate aes as raes; +extern crate aes_ctr; +extern crate block_modes; pub mod aes; pub mod aes_gcm; diff --git a/parity-crypto/src/pbkdf2.rs b/parity-crypto/src/pbkdf2.rs index d210f6f65..84ccca6ac 100644 --- a/parity-crypto/src/pbkdf2.rs +++ b/parity-crypto/src/pbkdf2.rs @@ -26,3 +26,28 @@ pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) { pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..]) } + + +#[cfg(test)] +::tests_pbkdf2!(); + +#[cfg(test)] +#[macro_export] +macro_rules! tests_pbkdf2 { + () => { + +mod test { + use super::*; + #[test] + fn basic_test() { + let mut dest = [0;32]; + let salt = [5;32]; + let secret = [7;32]; + sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); + let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; + assert_eq!(res, dest); + } +} + +} +} diff --git a/parity-crypto/src/scrypt.rs b/parity-crypto/src/scrypt.rs index d47e55ed2..65519962e 100644 --- a/parity-crypto/src/scrypt.rs +++ b/parity-crypto/src/scrypt.rs @@ -15,8 +15,10 @@ // along with Parity. If not, see . use error::ScryptError; -use rcrypto::scrypt::{scrypt, ScryptParams}; use super::{KEY_LENGTH_AES, KEY_LENGTH}; +use rscrypt::{scrypt, ScryptParams}; +#[cfg(test)] +use std::io::Error; pub fn derive_key(pass: &[u8], salt: &[u8], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), ScryptError> { // sanity checks @@ -30,9 +32,32 @@ pub fn derive_key(pass: &[u8], salt: &[u8], n: u32, p: u32, r: u32) -> Result<(V } let mut derived_key = vec![0u8; KEY_LENGTH]; - let scrypt_params = ScryptParams::new(log_n, r, p); - scrypt(pass, salt, &scrypt_params, &mut derived_key); + let scrypt_params = ScryptParams::new(log_n, r, p)?; + scrypt(pass, salt, &scrypt_params, &mut derived_key)?; let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) } + + +// test is build from previous crypto lib behaviour, values may be incorrect +// if previous crypto lib got a bug. +#[test] +pub fn test_derive() -> Result<(),Error> { + let pass = include_bytes!("../test/pass1"); + let salt_v = include_bytes!("../test/salt1"); + let mut salt = [0;32]; + salt.copy_from_slice(&salt_v[..32]); + let r1 = include_bytes!("../test/right1_1"); + let r2 = include_bytes!("../test/right1_2"); + let l1 = include_bytes!("../test/left1_1"); + let l2 = include_bytes!("../test/left1_2"); + + let (l,r) = derive_key(&pass[..],&salt, 262, 1, 8).unwrap(); + assert!(l == r1); + assert!(r == l1); + let (l,r) = derive_key(&pass[..],&salt, 144, 4, 4).unwrap(); + assert!(l == r2); + assert!(r == l2); + Ok(()) +} diff --git a/parity-crypto/test/content b/parity-crypto/test/content new file mode 100644 index 000000000..e3db0a16f --- /dev/null +++ b/parity-crypto/test/content @@ -0,0 +1,2 @@ +Some content to test aes, +not to much , only very basic test to avoid obvious regression when switching libs. diff --git a/parity-crypto/test/key1 b/parity-crypto/test/key1 new file mode 100644 index 000000000..af39cda5a --- /dev/null +++ b/parity-crypto/test/key1 @@ -0,0 +1 @@ +anycontenttoreach128bitsize diff --git a/parity-crypto/test/left1_1 b/parity-crypto/test/left1_1 new file mode 100644 index 000000000..bea4e8929 --- /dev/null +++ b/parity-crypto/test/left1_1 @@ -0,0 +1 @@ +Zw-Cc—QX¦Òô{Ð \ No newline at end of file diff --git a/parity-crypto/test/left1_2 b/parity-crypto/test/left1_2 new file mode 100644 index 000000000..0f7a880de --- /dev/null +++ b/parity-crypto/test/left1_2 @@ -0,0 +1 @@ +ý{„ ¼YÄkàï燱}> \ No newline at end of file diff --git a/parity-crypto/test/pass1 b/parity-crypto/test/pass1 new file mode 100644 index 000000000..1b104ed7b --- /dev/null +++ b/parity-crypto/test/pass1 @@ -0,0 +1 @@ +mypass diff --git a/parity-crypto/test/result_128_cbc b/parity-crypto/test/result_128_cbc new file mode 100644 index 0000000000000000000000000000000000000000..94d657dd1e9f369cd4c8dc6821636c07fff643fa GIT binary patch literal 112 zcmV-$0FVEt_yt-EjMs{#eThsj^S>~+_ia`fEm7A1Gu^p^Vd}l~|7+4lJSp8PiMggK zK@!N9>HolO8EJE&(SGY=!13`D`B(HDlDfTY3G;*mX*Hq<>r`viJDzdlc%m}xdq%rc SNs Date: Fri, 30 Nov 2018 12:27:30 +0100 Subject: [PATCH 35/39] Test values directly define in code. --- parity-crypto/src/aes.rs | 26 +++++++++++++++++++------- parity-crypto/src/scrypt.rs | 15 +++++++-------- parity-crypto/test/content | 2 -- parity-crypto/test/key1 | 1 - parity-crypto/test/left1_1 | 1 - parity-crypto/test/left1_2 | 1 - parity-crypto/test/pass1 | 1 - parity-crypto/test/result_128_cbc | Bin 112 -> 0 bytes parity-crypto/test/result_128_ctr | 3 --- parity-crypto/test/right1_1 | 1 - parity-crypto/test/right1_2 | 1 - parity-crypto/test/salt1 | 1 - 12 files changed, 26 insertions(+), 27 deletions(-) delete mode 100644 parity-crypto/test/content delete mode 100644 parity-crypto/test/key1 delete mode 100644 parity-crypto/test/left1_1 delete mode 100644 parity-crypto/test/left1_2 delete mode 100644 parity-crypto/test/pass1 delete mode 100644 parity-crypto/test/result_128_cbc delete mode 100644 parity-crypto/test/result_128_ctr delete mode 100644 parity-crypto/test/right1_1 delete mode 100644 parity-crypto/test/right1_2 delete mode 100644 parity-crypto/test/salt1 diff --git a/parity-crypto/src/aes.rs b/parity-crypto/src/aes.rs index a9242f17d..cddf002da 100644 --- a/parity-crypto/src/aes.rs +++ b/parity-crypto/src/aes.rs @@ -168,17 +168,29 @@ mod tests { #[test] pub fn test_aes_short() -> Result<(),SymmError> { - let key = include_bytes!("../test/key1"); - let salt = include_bytes!("../test/salt1"); - let content = include_bytes!("../test/content"); - let ctr_enc = include_bytes!("../test/result_128_ctr"); - let cbc_enc = include_bytes!("../test/result_128_cbc"); + let key = [97, 110, 121, 99, 111, 110, 116, 101, 110, 116, 116, 111, 114, 101, 97, 99, 104, 49, 50, 56, 98, 105, 116, 115, 105, 122, 101, 10]; + let salt = [109, 121, 115, 97, 108, 116, 115, 104, 111, 117, 108, 100, 102, 105, 108, 108, 115, 111, 109, 109, 101, 98, 121, 116, 101, 108, 101, 110, 103, 116, 104, 10]; + let content = [83, 111, 109, 101, 32, 99, 111, 110, 116, 101, 110, 116, 32, 116, 111, 32, 116, 101, 115, 116, + 32, 97, 101, 115, 44, 10, 110, 111, 116, 32, 116, 111, 32, 109, 117, 99, 104, 32, 44, 32, 111, 110, 108, 121, + 32, 118, 101, 114, 121, 32, 98, 97, 115, 105, 99, 32, 116, 101, 115, 116, 32, 116, 111, 32, 97, 118, 111, 105, + 100, 32, 111, 98, 118, 105, 111, 117, 115, 32, 114, 101, 103, 114, 101, 115, 115, 105, 111, 110, 32, 119, 104, + 101, 110, 32, 115, 119, 105, 116, 99, 104, 105, 110, 103, 32, 108, 105, 98, 115, 46, 10]; + let ctr_enc = [65, 55, 246, 75, 24, 117, 30, 233, 218, 139, 91, 251, 251, 179, 171, 69, 60, 244, 249, 44, 238, 60, + 10, 66, 71, 10, 199, 111, 54, 24, 124, 223, 153, 250, 159, 154, 164, 109, 232, 82, 20, 199, 182, 40, 174, 104, 64, + 203, 236, 94, 222, 184, 117, 54, 234, 189, 253, 122, 135, 121, 100, 44, 227, 241, 123, 120, 110, 188, 109, 148, 112, + 160, 131, 205, 116, 104, 232, 8, 22, 170, 80, 231, 155, 246, 255, 115, 101, 5, 234, 104, 220, 199, 192, 166, 181, 156, + 113, 255, 187, 51, 38, 128, 75, 29, 237, 178, 205, 98, 101, 110]; + let cbc_enc = [167, 248, 5, 90, 11, 140, 215, 138, 165, 125, 137, 76, 47, 243, 191, 48, 183, 247, 109, 86, 24, 45, + 81, 215, 0, 51, 221, 185, 131, 97, 234, 189, 244, 255, 107, 210, 70, 60, 41, 221, 43, 137, 185, 166, 42, 65, 18, 200, + 151, 233, 255, 192, 109, 25, 105, 115, 161, 209, 126, 235, 99, 192, 241, 241, 19, 249, 87, 244, 28, 146, 186, 189, 108, + 9, 243, 132, 4, 105, 53, 162, 8, 235, 84, 107, 213, 59, 158, 113, 227, 120, 162, 50, 237, 123, 70, 187, 83, 73, 146, 13, + 44, 191, 53, 4, 125, 207, 176, 45, 8, 153, 175, 198]; let mut dest = vec![0;110]; let mut dest_padded = vec![0;112]; let mut dest_padded2 = vec![0;128]; // TODO RustLib need an extra 16bytes in dest : looks extra buggy but function is not currently use (keep it private for now) - encrypt_128_cbc(&key[..16], &salt[..16], content, &mut dest_padded2)?; + encrypt_128_cbc(&key[..16], &salt[..16], &content, &mut dest_padded2)?; assert!(&dest_padded2[..112] == &cbc_enc[..]); - encrypt_128_ctr(&key[..16], &salt[..16], content, &mut dest)?; + encrypt_128_ctr(&key[..16], &salt[..16], &content, &mut dest)?; assert!(&dest[..] == &ctr_enc[..]); let mut content_data = content.to_vec(); inplace_encrypt_128_ctr(&key[..16], &salt[..16], &mut content_data[..])?; diff --git a/parity-crypto/src/scrypt.rs b/parity-crypto/src/scrypt.rs index 65519962e..c5ba18833 100644 --- a/parity-crypto/src/scrypt.rs +++ b/parity-crypto/src/scrypt.rs @@ -44,14 +44,13 @@ pub fn derive_key(pass: &[u8], salt: &[u8], n: u32, p: u32, r: u32) -> Result<(V // if previous crypto lib got a bug. #[test] pub fn test_derive() -> Result<(),Error> { - let pass = include_bytes!("../test/pass1"); - let salt_v = include_bytes!("../test/salt1"); - let mut salt = [0;32]; - salt.copy_from_slice(&salt_v[..32]); - let r1 = include_bytes!("../test/right1_1"); - let r2 = include_bytes!("../test/right1_2"); - let l1 = include_bytes!("../test/left1_1"); - let l2 = include_bytes!("../test/left1_2"); + let pass = [109, 121, 112, 97, 115, 115, 10]; + let salt = [109, 121, 115, 97, 108, 116, 115, 104, 111, 117, 108, 100, 102, 105, + 108, 108, 115, 111, 109, 109, 101, 98, 121, 116, 101, 108, 101, 110, 103, 116, 104, 10]; + let r1 = [93, 134, 79, 68, 223, 27, 44, 174, 236, 184, 179, 203, 74, 139, 73, 66]; + let r2 = [2, 24, 239, 131, 172, 164, 18, 171, 132, 207, 22, 217, 150, 20, 203, 37]; + let l1 = [6, 90, 119, 45, 67, 2, 99, 151, 81, 88, 166, 210, 244, 19, 123, 208]; + let l2 = [253, 123, 132, 12, 188, 89, 196, 2, 107, 224, 239, 231, 135, 177, 125, 62]; let (l,r) = derive_key(&pass[..],&salt, 262, 1, 8).unwrap(); assert!(l == r1); diff --git a/parity-crypto/test/content b/parity-crypto/test/content deleted file mode 100644 index e3db0a16f..000000000 --- a/parity-crypto/test/content +++ /dev/null @@ -1,2 +0,0 @@ -Some content to test aes, -not to much , only very basic test to avoid obvious regression when switching libs. diff --git a/parity-crypto/test/key1 b/parity-crypto/test/key1 deleted file mode 100644 index af39cda5a..000000000 --- a/parity-crypto/test/key1 +++ /dev/null @@ -1 +0,0 @@ -anycontenttoreach128bitsize diff --git a/parity-crypto/test/left1_1 b/parity-crypto/test/left1_1 deleted file mode 100644 index bea4e8929..000000000 --- a/parity-crypto/test/left1_1 +++ /dev/null @@ -1 +0,0 @@ -Zw-Cc—QX¦Òô{Ð \ No newline at end of file diff --git a/parity-crypto/test/left1_2 b/parity-crypto/test/left1_2 deleted file mode 100644 index 0f7a880de..000000000 --- a/parity-crypto/test/left1_2 +++ /dev/null @@ -1 +0,0 @@ -ý{„ ¼YÄkàï燱}> \ No newline at end of file diff --git a/parity-crypto/test/pass1 b/parity-crypto/test/pass1 deleted file mode 100644 index 1b104ed7b..000000000 --- a/parity-crypto/test/pass1 +++ /dev/null @@ -1 +0,0 @@ -mypass diff --git a/parity-crypto/test/result_128_cbc b/parity-crypto/test/result_128_cbc deleted file mode 100644 index 94d657dd1e9f369cd4c8dc6821636c07fff643fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmV-$0FVEt_yt-EjMs{#eThsj^S>~+_ia`fEm7A1Gu^p^Vd}l~|7+4lJSp8PiMggK zK@!N9>HolO8EJE&(SGY=!13`D`B(HDlDfTY3G;*mX*Hq<>r`viJDzdlc%m}xdq%rc SNs Date: Fri, 30 Nov 2018 12:37:51 +0100 Subject: [PATCH 36/39] Missing from merge --- parity-crypto/test/content | 2 -- parity-crypto/test/key1 | 1 - parity-crypto/test/left1_1 | 1 - parity-crypto/test/left1_2 | 1 - parity-crypto/test/pass1 | 1 - parity-crypto/test/result_128_cbc | Bin 112 -> 0 bytes parity-crypto/test/result_128_ctr | 3 --- parity-crypto/test/right1_1 | 1 - parity-crypto/test/right1_2 | 1 - parity-crypto/test/salt1 | 1 - 10 files changed, 12 deletions(-) delete mode 100644 parity-crypto/test/content delete mode 100644 parity-crypto/test/key1 delete mode 100644 parity-crypto/test/left1_1 delete mode 100644 parity-crypto/test/left1_2 delete mode 100644 parity-crypto/test/pass1 delete mode 100644 parity-crypto/test/result_128_cbc delete mode 100644 parity-crypto/test/result_128_ctr delete mode 100644 parity-crypto/test/right1_1 delete mode 100644 parity-crypto/test/right1_2 delete mode 100644 parity-crypto/test/salt1 diff --git a/parity-crypto/test/content b/parity-crypto/test/content deleted file mode 100644 index e3db0a16f..000000000 --- a/parity-crypto/test/content +++ /dev/null @@ -1,2 +0,0 @@ -Some content to test aes, -not to much , only very basic test to avoid obvious regression when switching libs. diff --git a/parity-crypto/test/key1 b/parity-crypto/test/key1 deleted file mode 100644 index af39cda5a..000000000 --- a/parity-crypto/test/key1 +++ /dev/null @@ -1 +0,0 @@ -anycontenttoreach128bitsize diff --git a/parity-crypto/test/left1_1 b/parity-crypto/test/left1_1 deleted file mode 100644 index bea4e8929..000000000 --- a/parity-crypto/test/left1_1 +++ /dev/null @@ -1 +0,0 @@ -Zw-Cc—QX¦Òô{Ð \ No newline at end of file diff --git a/parity-crypto/test/left1_2 b/parity-crypto/test/left1_2 deleted file mode 100644 index 0f7a880de..000000000 --- a/parity-crypto/test/left1_2 +++ /dev/null @@ -1 +0,0 @@ -ý{„ ¼YÄkàï燱}> \ No newline at end of file diff --git a/parity-crypto/test/pass1 b/parity-crypto/test/pass1 deleted file mode 100644 index 1b104ed7b..000000000 --- a/parity-crypto/test/pass1 +++ /dev/null @@ -1 +0,0 @@ -mypass diff --git a/parity-crypto/test/result_128_cbc b/parity-crypto/test/result_128_cbc deleted file mode 100644 index 94d657dd1e9f369cd4c8dc6821636c07fff643fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112 zcmV-$0FVEt_yt-EjMs{#eThsj^S>~+_ia`fEm7A1Gu^p^Vd}l~|7+4lJSp8PiMggK zK@!N9>HolO8EJE&(SGY=!13`D`B(HDlDfTY3G;*mX*Hq<>r`viJDzdlc%m}xdq%rc SNs Date: Mon, 3 Dec 2018 16:50:10 +0100 Subject: [PATCH 37/39] Move tests in their own file and remove macros --- parity-crypto/src/{hmac.rs => hmac/mod.rs} | 47 +----------------- parity-crypto/src/hmac/test.rs | 49 +++++++++++++++++++ .../src/{pbkdf2.rs => pbkdf2/mod.rs} | 23 +-------- parity-crypto/src/pbkdf2/test.rs | 26 ++++++++++ 4 files changed, 77 insertions(+), 68 deletions(-) rename parity-crypto/src/{hmac.rs => hmac/mod.rs} (62%) create mode 100644 parity-crypto/src/hmac/test.rs rename parity-crypto/src/{pbkdf2.rs => pbkdf2/mod.rs} (70%) create mode 100644 parity-crypto/src/pbkdf2/test.rs diff --git a/parity-crypto/src/hmac.rs b/parity-crypto/src/hmac/mod.rs similarity index 62% rename from parity-crypto/src/hmac.rs rename to parity-crypto/src/hmac/mod.rs index 0526367a4..1372fbe10 100644 --- a/parity-crypto/src/hmac.rs +++ b/parity-crypto/src/hmac/mod.rs @@ -87,50 +87,5 @@ pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { hmac::verify(&k.0, data, sig).is_ok() } - -#[cfg(test)] -::tests_hmac!(); - #[cfg(test)] -#[macro_export] -macro_rules! tests_hmac { - () => { - -pub mod test { - use super::*; - #[test] - fn simple_mac_and_verify() { - let input = b"Some bytes"; - let big_input = vec![7u8;2000]; - - let key1 = vec![3u8;64]; - let key2 = vec![4u8;128]; - - let sig_key1 = SigKey::sha256(&key1[..]); - let sig_key2 = SigKey::sha512(&key2[..]); - - let mut signer1 = Signer::with(&sig_key1); - let mut signer2 = Signer::with(&sig_key2); - - signer1.update(&input[..]); - for i in 0 .. big_input.len() / 33 { - signer2.update(&big_input[i*33..(i+1)*33]); - } - signer2.update(&big_input[(big_input.len() / 33)*33..]); - let sig1 = signer1.sign(); - assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); - let sig2 = signer2.sign(); - assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); - assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); - assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); - let verif_key1 = VerifyKey::sha256(&key1[..]); - let verif_key2 = VerifyKey::sha512(&key2[..]); - assert!(verify(&verif_key1, &input[..], &sig1[..])); - assert!(verify(&verif_key2, &big_input[..], &sig2[..])); - - } -} - -} -} - +mod test; diff --git a/parity-crypto/src/hmac/test.rs b/parity-crypto/src/hmac/test.rs new file mode 100644 index 000000000..a04e247e5 --- /dev/null +++ b/parity-crypto/src/hmac/test.rs @@ -0,0 +1,49 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + + +use super::*; +#[test] +fn simple_mac_and_verify() { + let input = b"Some bytes"; + let big_input = vec![7u8;2000]; + + let key1 = vec![3u8;64]; + let key2 = vec![4u8;128]; + + let sig_key1 = SigKey::sha256(&key1[..]); + let sig_key2 = SigKey::sha512(&key2[..]); + + let mut signer1 = Signer::with(&sig_key1); + let mut signer2 = Signer::with(&sig_key2); + + signer1.update(&input[..]); + for i in 0 .. big_input.len() / 33 { + signer2.update(&big_input[i*33..(i+1)*33]); + } + signer2.update(&big_input[(big_input.len() / 33)*33..]); + let sig1 = signer1.sign(); + assert_eq!(&sig1[..], [223, 208, 90, 69, 144, 95, 145, 180, 56, 155, 78, 40, 86, 238, 205, 81, 160, 245, 88, 145, 164, 67, 254, 180, 202, 107, 93, 249, 64, 196, 86, 225]); + let sig2 = signer2.sign(); + assert_eq!(&sig2[..], &[29, 63, 46, 122, 27, 5, 241, 38, 86, 197, 91, 79, 33, 107, 152, 195, 118, 221, 117, 119, 84, 114, 46, 65, 243, 157, 105, 12, 147, 176, 190, 37, 210, 164, 152, 8, 58, 243, 59, 206, 80, 10, 230, 197, 255, 110, 191, 180, 93, 22, 255, 0, 99, 79, 237, 229, 209, 199, 125, 83, 15, 179, 134, 89][..]); + assert_eq!(&sig1[..], &sign(&sig_key1, &input[..])[..]); + assert_eq!(&sig2[..], &sign(&sig_key2, &big_input[..])[..]); + let verif_key1 = VerifyKey::sha256(&key1[..]); + let verif_key2 = VerifyKey::sha512(&key2[..]); + assert!(verify(&verif_key1, &input[..], &sig1[..])); + assert!(verify(&verif_key2, &big_input[..], &sig2[..])); + +} diff --git a/parity-crypto/src/pbkdf2.rs b/parity-crypto/src/pbkdf2/mod.rs similarity index 70% rename from parity-crypto/src/pbkdf2.rs rename to parity-crypto/src/pbkdf2/mod.rs index 84ccca6ac..7ff4a2715 100644 --- a/parity-crypto/src/pbkdf2.rs +++ b/parity-crypto/src/pbkdf2/mod.rs @@ -29,25 +29,4 @@ pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { #[cfg(test)] -::tests_pbkdf2!(); - -#[cfg(test)] -#[macro_export] -macro_rules! tests_pbkdf2 { - () => { - -mod test { - use super::*; - #[test] - fn basic_test() { - let mut dest = [0;32]; - let salt = [5;32]; - let secret = [7;32]; - sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); - let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; - assert_eq!(res, dest); - } -} - -} -} +mod test; diff --git a/parity-crypto/src/pbkdf2/test.rs b/parity-crypto/src/pbkdf2/test.rs new file mode 100644 index 000000000..99dc225ab --- /dev/null +++ b/parity-crypto/src/pbkdf2/test.rs @@ -0,0 +1,26 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use super::*; +#[test] +fn basic_test() { + let mut dest = [0;32]; + let salt = [5;32]; + let secret = [7;32]; + sha256(3, Salt(&salt[..]), Secret(&secret[..]), &mut dest); + let res = [242, 33, 31, 124, 36, 223, 179, 185, 206, 175, 190, 253, 85, 33, 23, 126, 141, 29, 23, 97, 66, 63, 51, 196, 27, 255, 135, 206, 74, 137, 172, 87]; + assert_eq!(res, dest); +} From 3c36377cb663317c0b0c894f8c102534488d279b Mon Sep 17 00:00:00 2001 From: cheme Date: Mon, 3 Dec 2018 16:58:28 +0100 Subject: [PATCH 38/39] remove part of macro (TODO remove all and move alt to module) --- parity-crypto/src/hmac_alt.rs | 3 ++- parity-crypto/src/pbkdf2_alt.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/parity-crypto/src/hmac_alt.rs b/parity-crypto/src/hmac_alt.rs index 05808cd34..29ac47d6f 100644 --- a/parity-crypto/src/hmac_alt.rs +++ b/parity-crypto/src/hmac_alt.rs @@ -84,4 +84,5 @@ pub fn verify(k: &VerifyKey, data: &[u8], sig: &[u8]) -> bool { } #[cfg(test)] -::tests_hmac!(); +#[path = "hmac/test.rs"] +mod test; diff --git a/parity-crypto/src/pbkdf2_alt.rs b/parity-crypto/src/pbkdf2_alt.rs index 18d0331e4..4f6b43655 100644 --- a/parity-crypto/src/pbkdf2_alt.rs +++ b/parity-crypto/src/pbkdf2_alt.rs @@ -33,5 +33,5 @@ pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) { #[cfg(test)] -::tests_pbkdf2!(); - +#[path = "pbkdf2/test.rs"] +mod test; From ec212b000853073a8ea70d9cf5aa9a63b1dc5f0f Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 17 May 2019 10:08:07 +0200 Subject: [PATCH 39/39] rename of package is now stable --- parity-crypto/Cargo.toml | 10 ++++------ parity-crypto/libsecp256k1/Cargo.toml | 10 ---------- parity-crypto/libsecp256k1/src/lib.rs | 23 ----------------------- parity-crypto/src/secp256k1_alt.rs | 2 +- 4 files changed, 5 insertions(+), 40 deletions(-) delete mode 100644 parity-crypto/libsecp256k1/Cargo.toml delete mode 100644 parity-crypto/libsecp256k1/src/lib.rs diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index 615c73787..2feda7394 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -32,22 +32,20 @@ parity-util-mem = { version = "0.1", path = "../parity-util-mem" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] #secp256k1 = "0.11" secp256k1 = { git = "https://github.com/cheme/rust-secp256k1", branch = "parity-eth" } -libsecp256k1 = { path = "./libsecp256k1", optional = true } +libsecp256k1_alt = { version = "0.2", optional = true, package = "libsecp256k1" } [target.'cfg(target_arch = "wasm32")'.dependencies] subtle = { version = "1.0" } -# libsecp256k1 = { version = "0.1", package = "libsecp256k1" } // requires 'rename-dependency' in stable -libsecp256k1 = { path = "./libsecp256k1" } +libsecp256k1_alt = { version = "0.2", package = "libsecp256k1" } [dev-dependencies] -# libsecp256k1 = { version = "0.1", package = "libsecp256k1" } // requires 'rename-dependency' in stable -libsecp256k1 = { path = "./libsecp256k1" } +libsecp256k1_alt = { version = "0.2", package = "libsecp256k1" } #criterion = "0.2.11" rand = "0.4" [features] # expose alternative wasm32 implementation for testing and benchmarks -alt = ["libsecp256k1"] +alt = ["libsecp256k1_alt"] nightly = ["subtle/nightly"] volatile-erase = ["parity-util-mem/volatile-erase"] diff --git a/parity-crypto/libsecp256k1/Cargo.toml b/parity-crypto/libsecp256k1/Cargo.toml deleted file mode 100644 index a78212d42..000000000 --- a/parity-crypto/libsecp256k1/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "libsecp256k1" -version = "0.0.1" -authors = ["Parity Technologies "] -repository = "https://github.com/paritytech/parity-common" -description = "Renaming crate for libsecp256k1." -license = "GPL-3.0" - -[dependencies] -libsecp256k1 = { version = "0.2" } diff --git a/parity-crypto/libsecp256k1/src/lib.rs b/parity-crypto/libsecp256k1/src/lib.rs deleted file mode 100644 index a309d7b62..000000000 --- a/parity-crypto/libsecp256k1/src/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Renaming crate for libsecp256k1, this crate should be drop as soon as -//! 'renaming-crates' functionality makes it to stable. - - -extern crate secp256k1; - -pub use secp256k1::*; diff --git a/parity-crypto/src/secp256k1_alt.rs b/parity-crypto/src/secp256k1_alt.rs index 737a21b97..73b8793d1 100644 --- a/parity-crypto/src/secp256k1_alt.rs +++ b/parity-crypto/src/secp256k1_alt.rs @@ -16,7 +16,7 @@ //! secp256k1 for parity. -extern crate libsecp256k1 as secp256k1; +extern crate libsecp256k1_alt as secp256k1; use clear_on_drop::clear::Clear; use clear_on_drop::ClearOnDrop;