all crypto functions
This commit is contained in:
parent
03f5d3d4b0
commit
ea5bee9a36
|
@ -1,6 +1,6 @@
|
||||||
use block_header::BlockHeader;
|
use block_header::BlockHeader;
|
||||||
use compact_integer::CompactInteger;
|
use compact_integer::CompactInteger;
|
||||||
use crypto::dhash;
|
use crypto::dhash256;
|
||||||
use hash::H256;
|
use hash::H256;
|
||||||
use merkle_root::merkle_root;
|
use merkle_root::merkle_root;
|
||||||
use reader::{Deserializable, Reader, Error as ReaderError};
|
use reader::{Deserializable, Reader, Error as ReaderError};
|
||||||
|
@ -38,7 +38,7 @@ impl Deserializable for Block {
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn hash(&self) -> H256 {
|
pub fn hash(&self) -> H256 {
|
||||||
dhash(&serialize(&self.block_header))
|
dhash256(&serialize(&self.block_header))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns block's merkle root.
|
/// Returns block's merkle root.
|
||||||
|
|
120
src/crypto.rs
120
src/crypto.rs
|
@ -1,6 +1,8 @@
|
||||||
|
use rcrypto::sha1::Sha1;
|
||||||
use rcrypto::sha2::Sha256;
|
use rcrypto::sha2::Sha256;
|
||||||
|
use rcrypto::ripemd160::Ripemd160;
|
||||||
use rcrypto::digest::Digest;
|
use rcrypto::digest::Digest;
|
||||||
use hash::H256;
|
use hash::{H160, H256};
|
||||||
|
|
||||||
/// SHA-256
|
/// SHA-256
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -12,6 +14,46 @@ pub fn hash(input: &[u8]) -> H256 {
|
||||||
result
|
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 {
|
pub struct DHash256 {
|
||||||
hasher: Sha256,
|
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
|
/// Double SHA-256
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dhash(input: &[u8]) -> H256 {
|
pub fn dhash256(input: &[u8]) -> H256 {
|
||||||
let mut result = [0u8; 32];
|
let mut result = [0u8; 32];
|
||||||
let mut hasher = DHash256::new();
|
let mut hasher = DHash256::new();
|
||||||
hasher.input(input);
|
hasher.input(input);
|
||||||
|
@ -61,13 +143,41 @@ pub fn dhash(input: &[u8]) -> H256 {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::dhash;
|
use super::{ripemd160, sha1, sha256, dhash160, dhash256};
|
||||||
use hex::FromHex;
|
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]
|
#[test]
|
||||||
fn test_double_hash() {
|
fn test_dhash256() {
|
||||||
let expected = "9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50".from_hex().unwrap();
|
let expected = "9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50".from_hex().unwrap();
|
||||||
let result = dhash(b"hello");
|
let result = dhash256(b"hello");
|
||||||
assert_eq!(result.to_vec(), expected);
|
assert_eq!(result.to_vec(), expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crypto::dhash;
|
use crypto::dhash256;
|
||||||
|
|
||||||
/// Data checksum
|
/// Data checksum
|
||||||
pub fn checksum(data: &[u8]) -> [u8; 4] {
|
pub fn checksum(data: &[u8]) -> [u8; 4] {
|
||||||
let mut result = [0u8; 4];
|
let mut result = [0u8; 4];
|
||||||
result.copy_from_slice(&dhash(data)[0..4]);
|
result.copy_from_slice(&dhash256(data)[0..4]);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl KeyPair {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crypto::dhash;
|
use crypto::dhash256;
|
||||||
use keys::Public;
|
use keys::Public;
|
||||||
use super::KeyPair;
|
use super::KeyPair;
|
||||||
|
|
||||||
|
@ -120,25 +120,25 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_sign(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool {
|
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();
|
let kp = KeyPair::from_private(secret.into()).unwrap();
|
||||||
kp.private().sign(&message).unwrap() == signature.into()
|
kp.private().sign(&message).unwrap() == signature.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_verify(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool {
|
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();
|
let kp = KeyPair::from_private(secret.into()).unwrap();
|
||||||
kp.public().verify(&message, &signature.into()).unwrap()
|
kp.public().verify(&message, &signature.into()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_sign_compact(secret: &'static str, raw_message: &[u8], signature: &'static str) -> bool {
|
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();
|
let kp = KeyPair::from_private(secret.into()).unwrap();
|
||||||
kp.private().sign_compact(&message).unwrap() == signature.into()
|
kp.private().sign_compact(&message).unwrap() == signature.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_recover_compact(secret: &'static str, raw_message: &[u8]) -> bool {
|
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 kp = KeyPair::from_private(secret.into()).unwrap();
|
||||||
let signature = kp.private().sign_compact(&message).unwrap();
|
let signature = kp.private().sign_compact(&message).unwrap();
|
||||||
let recovered = Public::recover_compact(&message, &signature).unwrap();
|
let recovered = Public::recover_compact(&message, &signature).unwrap();
|
||||||
|
|
|
@ -2,10 +2,8 @@ use std::fmt;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use secp256k1::key;
|
use secp256k1::key;
|
||||||
use secp256k1::{Message as SecpMessage, RecoveryId, RecoverableSignature, Error as SecpError, Signature as SecpSignature};
|
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 hex::ToHex;
|
||||||
|
use crypto::dhash160;
|
||||||
use hash::{H264, H520};
|
use hash::{H264, H520};
|
||||||
use keys::{AddressHash, Error, CompactSignature, Signature, Message, SECP256K1};
|
use keys::{AddressHash, Error, CompactSignature, Signature, Message, SECP256K1};
|
||||||
|
|
||||||
|
@ -16,15 +14,7 @@ pub enum Public {
|
||||||
|
|
||||||
impl Public {
|
impl Public {
|
||||||
pub fn address_hash(&self) -> AddressHash {
|
pub fn address_hash(&self) -> AddressHash {
|
||||||
let mut tmp = [0u8; 32];
|
dhash160(self)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self, message: &Message, signature: &Signature) -> Result<bool, Error> {
|
pub fn verify(&self, message: &Message, signature: &Signature) -> Result<bool, Error> {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crypto::dhash;
|
use crypto::dhash256;
|
||||||
use hash::{H256, H512};
|
use hash::{H256, H512};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -19,14 +19,14 @@ pub fn merkle_root(hashes: &[H256]) -> H256 {
|
||||||
let mut row = vec![];
|
let mut row = vec![];
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i + 1 < hashes.len() {
|
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
|
i += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// duplicate the last element if len is not even
|
// duplicate the last element if len is not even
|
||||||
if hashes.len() % 2 == 1 {
|
if hashes.len() % 2 == 1 {
|
||||||
let last = hashes[hashes.len() - 1];
|
let last = hashes[hashes.len() - 1];
|
||||||
row.push(dhash(&concat(&last, &last)));
|
row.push(dhash256(&concat(&last, &last)));
|
||||||
}
|
}
|
||||||
|
|
||||||
merkle_root(&row)
|
merkle_root(&row)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use keys::{Public, Signature};
|
use keys::{Public, Signature};
|
||||||
use hash::H256;
|
use hash::H256;
|
||||||
use transaction::{Transaction, SEQUENCE_LOCKTIME_DISABLE_FLAG};
|
use transaction::{Transaction, SEQUENCE_LOCKTIME_DISABLE_FLAG};
|
||||||
|
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
|
||||||
use script::{script, Script, Num, VerificationFlags, Opcode, Error, Instruction};
|
use script::{script, Script, Num, VerificationFlags, Opcode, Error, Instruction};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
@ -560,6 +561,33 @@ pub fn eval_script(
|
||||||
return Err(Error::EqualVerify);
|
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);
|
let result = Err(Error::InvalidStackOperation);
|
||||||
basic_test(&script, result, vec![]);
|
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![]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! https://en.bitcoin.it/wiki/Protocol_documentation#tx
|
//! https://en.bitcoin.it/wiki/Protocol_documentation#tx
|
||||||
|
|
||||||
use reader::{Deserializable, Reader, Error as ReaderError};
|
use reader::{Deserializable, Reader, Error as ReaderError};
|
||||||
use crypto::dhash;
|
use crypto::dhash256;
|
||||||
use hash::H256;
|
use hash::H256;
|
||||||
use stream::{Serializable, Stream, serialize};
|
use stream::{Serializable, Stream, serialize};
|
||||||
use compact_integer::CompactInteger;
|
use compact_integer::CompactInteger;
|
||||||
|
@ -147,7 +147,7 @@ impl Deserializable for Transaction {
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
pub fn hash(&self) -> H256 {
|
pub fn hash(&self) -> H256 {
|
||||||
dhash(&serialize(self))
|
dhash256(&serialize(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue