From ea5bee9a369207d11341cbef237165e90c64a509 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 9 Sep 2016 10:49:08 +0200 Subject: [PATCH] all crypto functions --- src/block.rs | 4 +- src/crypto.rs | 120 ++++++++++++++++++++++++++++++++++++-- src/keys/checksum.rs | 4 +- src/keys/keypair.rs | 10 ++-- src/keys/public.rs | 14 +---- src/merkle_root.rs | 6 +- src/script/interpreter.rs | 108 ++++++++++++++++++++++++++++++++++ src/transaction.rs | 4 +- 8 files changed, 239 insertions(+), 31 deletions(-) diff --git a/src/block.rs b/src/block.rs index 8e6ebcfa..21cab270 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,6 +1,6 @@ use block_header::BlockHeader; use compact_integer::CompactInteger; -use crypto::dhash; +use crypto::dhash256; use hash::H256; use merkle_root::merkle_root; use reader::{Deserializable, Reader, Error as ReaderError}; @@ -38,7 +38,7 @@ impl Deserializable for Block { impl Block { pub fn hash(&self) -> H256 { - dhash(&serialize(&self.block_header)) + dhash256(&serialize(&self.block_header)) } /// Returns block's merkle root. diff --git a/src/crypto.rs b/src/crypto.rs index 727e6f40..d67e7f82 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -1,6 +1,8 @@ +use rcrypto::sha1::Sha1; use rcrypto::sha2::Sha256; +use rcrypto::ripemd160::Ripemd160; use rcrypto::digest::Digest; -use hash::H256; +use hash::{H160, H256}; /// SHA-256 #[inline] @@ -12,6 +14,46 @@ pub fn hash(input: &[u8]) -> H256 { result } +pub struct DHash160 { + sha256: Sha256, + ripemd: Ripemd160, +} + +impl DHash160 { + pub fn new() -> Self { + DHash160 { + sha256: Sha256::new(), + ripemd: Ripemd160::new(), + } + } +} + +impl Digest for DHash160 { + fn input(&mut self, d: &[u8]) { + self.sha256.input(d) + } + + fn result(&mut self, out: &mut [u8]) { + let mut tmp = [0u8; 32]; + self.sha256.result(&mut tmp); + self.ripemd.input(&tmp); + self.ripemd.result(out); + self.ripemd.reset(); + } + + fn reset(&mut self) { + self.sha256.reset(); + } + + fn output_bits(&self) -> usize { + 160 + } + + fn block_size(&self) -> usize { + 64 + } +} + pub struct DHash256 { hasher: Sha256, } @@ -49,9 +91,49 @@ impl Digest for DHash256 { } } +/// RIPEMD160 +#[inline] +pub fn ripemd160(input: &[u8]) -> H160 { + let mut result = [0u8; 20]; + let mut hasher = Ripemd160::new(); + hasher.input(input); + hasher.result(&mut result); + result +} + +/// SHA-1 +#[inline] +pub fn sha1(input: &[u8]) -> H160 { + let mut result = [0u8; 20]; + let mut hasher = Sha1::new(); + hasher.input(input); + hasher.result(&mut result); + result +} + +/// SHA-256 +#[inline] +pub fn sha256(input: &[u8]) -> H256 { + let mut result = [0u8; 32]; + let mut hasher = Sha256::new(); + hasher.input(input); + hasher.result(&mut result); + result +} + +/// SHA-256 and RIPEMD160 +#[inline] +pub fn dhash160(input: &[u8]) -> H160 { + let mut result = [0u8; 20]; + let mut hasher = DHash160::new(); + hasher.input(input); + hasher.result(&mut result); + result +} + /// Double SHA-256 #[inline] -pub fn dhash(input: &[u8]) -> H256 { +pub fn dhash256(input: &[u8]) -> H256 { let mut result = [0u8; 32]; let mut hasher = DHash256::new(); hasher.input(input); @@ -61,13 +143,41 @@ pub fn dhash(input: &[u8]) -> H256 { #[cfg(test)] mod tests { - use super::dhash; + use super::{ripemd160, sha1, sha256, dhash160, dhash256}; use hex::FromHex; + #[test] + fn test_ripemd160() { + let expected = "108f07b8382412612c048d07d13f814118445acd".from_hex().unwrap(); + let result = ripemd160(b"hello"); + assert_eq!(result.to_vec(), expected); + } + + #[test] + fn test_sha1() { + let expected = "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d".from_hex().unwrap(); + let result = sha1(b"hello"); + assert_eq!(result.to_vec(), expected); + } + + #[test] + fn test_sha256() { + let expected = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824".from_hex().unwrap(); + let result = sha256(b"hello"); + assert_eq!(result.to_vec(), expected); + } + + #[test] + fn test_dhash160() { + let expected = "b6a9c8c230722b7c748331a8b450f05566dc7d0f".from_hex().unwrap(); + let result = dhash160(b"hello"); + assert_eq!(result.to_vec(), expected); + } + #[test] - fn test_double_hash() { + fn test_dhash256() { let expected = "9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50".from_hex().unwrap(); - let result = dhash(b"hello"); + let result = dhash256(b"hello"); assert_eq!(result.to_vec(), expected); } } diff --git a/src/keys/checksum.rs b/src/keys/checksum.rs index 53663f46..1c38d878 100644 --- a/src/keys/checksum.rs +++ b/src/keys/checksum.rs @@ -1,8 +1,8 @@ -use crypto::dhash; +use crypto::dhash256; /// Data checksum pub fn checksum(data: &[u8]) -> [u8; 4] { let mut result = [0u8; 4]; - result.copy_from_slice(&dhash(data)[0..4]); + result.copy_from_slice(&dhash256(data)[0..4]); result } diff --git a/src/keys/keypair.rs b/src/keys/keypair.rs index a08b2ffb..114c06da 100644 --- a/src/keys/keypair.rs +++ b/src/keys/keypair.rs @@ -86,7 +86,7 @@ impl KeyPair { #[cfg(test)] mod tests { - use crypto::dhash; + use crypto::dhash256; use keys::Public; use super::KeyPair; @@ -120,25 +120,25 @@ mod tests { } fn check_sign(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool { - let message = dhash(raw_message); + let message = dhash256(raw_message); let kp = KeyPair::from_private(secret.into()).unwrap(); kp.private().sign(&message).unwrap() == signature.into() } fn check_verify(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool { - let message = dhash(raw_message); + let message = dhash256(raw_message); let kp = KeyPair::from_private(secret.into()).unwrap(); kp.public().verify(&message, &signature.into()).unwrap() } fn check_sign_compact(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool { - let message = dhash(raw_message); + let message = dhash256(raw_message); let kp = KeyPair::from_private(secret.into()).unwrap(); kp.private().sign_compact(&message).unwrap() == signature.into() } fn check_recover_compact(secret: &'static str, raw_message: &[u8]) -> bool { - let message = dhash(raw_message); + let message = dhash256(raw_message); let kp = KeyPair::from_private(secret.into()).unwrap(); let signature = kp.private().sign_compact(&message).unwrap(); let recovered = Public::recover_compact(&message, &signature).unwrap(); diff --git a/src/keys/public.rs b/src/keys/public.rs index 0e0cc9c0..68364169 100644 --- a/src/keys/public.rs +++ b/src/keys/public.rs @@ -2,10 +2,8 @@ use std::fmt; use std::ops::Deref; use secp256k1::key; use secp256k1::{Message as SecpMessage, RecoveryId, RecoverableSignature, Error as SecpError, Signature as SecpSignature}; -use rcrypto::sha2::Sha256; -use rcrypto::ripemd160::Ripemd160; -use rcrypto::digest::Digest; use hex::ToHex; +use crypto::dhash160; use hash::{H264, H520}; use keys::{AddressHash, Error, CompactSignature, Signature, Message, SECP256K1}; @@ -16,15 +14,7 @@ pub enum Public { impl Public { pub fn address_hash(&self) -> AddressHash { - let mut tmp = [0u8; 32]; - let mut result = [0u8; 20]; - let mut sha2 = Sha256::new(); - let mut rmd = Ripemd160::new(); - sha2.input(self); - sha2.result(&mut tmp); - rmd.input(&tmp); - rmd.result(&mut result); - result + dhash160(self) } pub fn verify(&self, message: &Message, signature: &Signature) -> Result { diff --git a/src/merkle_root.rs b/src/merkle_root.rs index e4c68763..e8953c41 100644 --- a/src/merkle_root.rs +++ b/src/merkle_root.rs @@ -1,4 +1,4 @@ -use crypto::dhash; +use crypto::dhash256; use hash::{H256, H512}; #[inline] @@ -19,14 +19,14 @@ pub fn merkle_root(hashes: &[H256]) -> H256 { let mut row = vec![]; let mut i = 0; while i + 1 < hashes.len() { - row.push(dhash(&concat(&hashes[i], &hashes[i + 1]))); + row.push(dhash256(&concat(&hashes[i], &hashes[i + 1]))); i += 2 } // duplicate the last element if len is not even if hashes.len() % 2 == 1 { let last = hashes[hashes.len() - 1]; - row.push(dhash(&concat(&last, &last))); + row.push(dhash256(&concat(&last, &last))); } merkle_root(&row) diff --git a/src/script/interpreter.rs b/src/script/interpreter.rs index a58d566d..644db6d6 100644 --- a/src/script/interpreter.rs +++ b/src/script/interpreter.rs @@ -1,6 +1,7 @@ use keys::{Public, Signature}; use hash::H256; use transaction::{Transaction, SEQUENCE_LOCKTIME_DISABLE_FLAG}; +use crypto::{sha1, sha256, dhash160, dhash256, ripemd160}; use script::{script, Script, Num, VerificationFlags, Opcode, Error, Instruction}; #[derive(Debug, PartialEq, Clone, Copy)] @@ -560,6 +561,33 @@ pub fn eval_script( return Err(Error::EqualVerify); } }, + + // several opcodes here + Opcode::OP_RIPEMD160 => { + try!(require_not_empty(stack)); + let v = ripemd160(&stack.pop().unwrap()); + stack.push(v.to_vec()); + }, + Opcode::OP_SHA1 => { + try!(require_not_empty(stack)); + let v = sha1(&stack.pop().unwrap()); + stack.push(v.to_vec()); + }, + Opcode::OP_SHA256 => { + try!(require_not_empty(stack)); + let v = sha256(&stack.pop().unwrap()); + stack.push(v.to_vec()); + }, + Opcode::OP_HASH160 => { + try!(require_not_empty(stack)); + let v = dhash160(&stack.pop().unwrap()); + stack.push(v.to_vec()); + }, + Opcode::OP_HASH256 => { + try!(require_not_empty(stack)); + let v = dhash256(&stack.pop().unwrap()); + stack.push(v.to_vec()); + }, _ => (), }, } @@ -726,4 +754,84 @@ mod tests { let result = Err(Error::InvalidStackOperation); basic_test(&script, result, vec![]); } + + #[test] + fn test_hash256() { + let script = Builder::default() + .push_data(b"hello") + .push_opcode(Opcode::OP_HASH256) + .into_script(); + let result = Ok(true); + let stack = vec!["9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50".from_hex().unwrap()]; + basic_test(&script, result, stack); + } + + #[test] + fn test_hash256_invalid_stack() { + let script = Builder::default() + .push_opcode(Opcode::OP_HASH256) + .into_script(); + let result = Err(Error::InvalidStackOperation); + basic_test(&script, result, vec![]); + } + + #[test] + fn test_ripemd160() { + let script = Builder::default() + .push_data(b"hello") + .push_opcode(Opcode::OP_RIPEMD160) + .into_script(); + let result = Ok(true); + let stack = vec!["108f07b8382412612c048d07d13f814118445acd".from_hex().unwrap()]; + basic_test(&script, result, stack); + } + + #[test] + fn test_ripemd160_invalid_stack() { + let script = Builder::default() + .push_opcode(Opcode::OP_RIPEMD160) + .into_script(); + let result = Err(Error::InvalidStackOperation); + basic_test(&script, result, vec![]); + } + + #[test] + fn test_sha1() { + let script = Builder::default() + .push_data(b"hello") + .push_opcode(Opcode::OP_SHA1) + .into_script(); + let result = Ok(true); + let stack = vec!["aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d".from_hex().unwrap()]; + basic_test(&script, result, stack); + } + + #[test] + fn test_sha1_invalid_stack() { + let script = Builder::default() + .push_opcode(Opcode::OP_SHA1) + .into_script(); + let result = Err(Error::InvalidStackOperation); + basic_test(&script, result, vec![]); + } + + #[test] + fn test_sha256() { + let script = Builder::default() + .push_data(b"hello") + .push_opcode(Opcode::OP_SHA256) + .into_script(); + let result = Ok(true); + let stack = vec!["2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824".from_hex().unwrap()]; + basic_test(&script, result, stack); + } + + #[test] + fn test_sha256_invalid_stack() { + let script = Builder::default() + .push_opcode(Opcode::OP_SHA256) + .into_script(); + let result = Err(Error::InvalidStackOperation); + basic_test(&script, result, vec![]); + } } diff --git a/src/transaction.rs b/src/transaction.rs index 968d6aba..7d2d71b9 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -3,7 +3,7 @@ //! https://en.bitcoin.it/wiki/Protocol_documentation#tx use reader::{Deserializable, Reader, Error as ReaderError}; -use crypto::dhash; +use crypto::dhash256; use hash::H256; use stream::{Serializable, Stream, serialize}; use compact_integer::CompactInteger; @@ -147,7 +147,7 @@ impl Deserializable for Transaction { impl Transaction { pub fn hash(&self) -> H256 { - dhash(&serialize(self)) + dhash256(&serialize(self)) } }