diff --git a/Cargo.toml b/Cargo.toml index 09d337a..7e3d9d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "Wyrd" +name = "wyrd_ns" version = "0.1.0" authors = ["Revertron "] edition = "2018" diff --git a/src/block.rs b/src/block.rs index 3e3ba3b..d3dbbc9 100644 --- a/src/block.rs +++ b/src/block.rs @@ -4,14 +4,14 @@ extern crate num_bigint; extern crate num_traits; use super::*; -use rand::{thread_rng, Rng}; use std::fmt::Debug; -use chrono::{Utc, DateTime}; +use chrono::Utc; use serde::{Serialize, Deserialize}; use num_bigint::BigUint; use num_traits::One; -use crypto::sha2::Sha512; +use crypto::sha2::Sha256; use crypto::digest::Digest; +use crate::keys::Key; #[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] pub struct Block { @@ -24,13 +24,13 @@ pub struct Block { pub nonce: u64, #[serde(skip_serializing_if = "Option::is_none")] pub transaction: Option, - pub prev_block_hash: Hash, - #[serde(skip_serializing_if = "Hash::is_default")] - pub hash: Hash, + pub prev_block_hash: Key, + #[serde(default, skip_serializing_if = "Key::is_empty")] + pub hash: Key, } impl Block { - pub fn new(index: u64, timestamp: i64, chain_id: u32, version: u32, prev_block_hash: Hash, transaction: Option) -> Self { + pub fn new(index: u64, timestamp: i64, chain_id: u32, version: u32, prev_block_hash: Key, transaction: Option) -> Self { Block { index, timestamp, @@ -41,7 +41,7 @@ impl Block { nonce: 0, transaction, prev_block_hash, - hash: Hash::default(), + hash: Key::default(), } } @@ -60,16 +60,16 @@ impl Block { } } - pub fn hash(data: &[u8]) -> Hash { - let mut buf: [u8; 64] = [0; 64]; - let mut digest = Sha512::new(); + pub fn hash(data: &[u8]) -> Key { + let mut buf: [u8; 32] = [0; 32]; + let mut digest = Sha256::new(); digest.input(data); digest.result(&mut buf); - Hash::from_vec(&buf.to_vec()) + Key::new(buf.to_vec()) } pub fn is_genesis(&self) -> bool { - self.index == 0 && self.transaction.is_none() && self.prev_block_hash == Hash::default() + self.index == 0 && self.transaction.is_none() && self.prev_block_hash == Key::default() } } diff --git a/src/blockchain.rs b/src/blockchain.rs index 5b73fef..df9e1aa 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -1,5 +1,5 @@ -use crate::{Block, Transaction, Hash}; -use chrono::{Utc, DateTime}; +use crate::{Block, Transaction, Key}; +use chrono::Utc; pub struct Blockchain { pub chain_id: u32, @@ -23,7 +23,7 @@ impl Blockchain { } pub fn genesis(chain_id: u32, version: u32) -> Block { - Block::new(0, Utc::now().timestamp(), chain_id, version, Hash::default(), None) + Block::new(0, Utc::now().timestamp(), chain_id, version, Key::zero32(), None) } pub fn add_block(&mut self, block: Block) { @@ -61,7 +61,7 @@ impl Blockchain { pub fn check_block_hash(block: &Block) -> bool { // We need to clear Hash value to rehash it without it for check :( let mut copy: Block = block.clone(); - copy.hash = Hash::default(); + copy.hash = Key::default(); let data = serde_json::to_string(©).unwrap(); Block::hash(data.as_bytes()) == block.hash } diff --git a/src/hash.rs b/src/hash.rs deleted file mode 100644 index d95efc3..0000000 --- a/src/hash.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::utils; -use std::cmp::min; -use serde::{Serialize, Deserialize, Serializer, Deserializer}; -use std::fmt; -use serde::de::{Error as DeError, Visitor}; -use serde::ser::SerializeSeq; -use serde::export::Formatter; -use serde::export::fmt::Error; -use std::ops::Deref; - -/// A hash consisting of all zeroes, used as a constant -pub const ZERO_HASH: Hash = Hash{ bytes: [0u8; 64]}; - -/// A hash struct -#[derive(Copy, Clone)] -pub struct Hash { - bytes: [u8; 64] -} - -impl Hash { - /// Size of a hash in bytes. - const LEN: usize = 64; - - pub fn new(bytes: [u8; 64]) -> Self { - Hash{bytes} - } - - /// Builds a Hash from a byte vector. If the vector is too short, it will be - /// completed by zeroes. If it's too long, it will be truncated. - pub fn from_vec(v: &[u8]) -> Hash { - let mut h = [0; Hash::LEN]; - let copy_size = min(v.len(), Hash::LEN); - h[..copy_size].copy_from_slice(&v[..copy_size]); - Hash::new(h) - } - - /// Converts the hash to a byte vector - pub fn to_vec(&self) -> Vec { - self.bytes.to_vec() - } - - /// Returns a byte slice of the hash contents. - pub fn as_bytes(&self) -> &[u8] { - &self.bytes - } - - /// Convert a hash to hex string format. - pub fn to_hex(&self) -> String { - utils::to_hex(self.to_vec().as_ref()) - } - - pub fn is_default(&self) -> bool { - utils::same_hash(&self.bytes, &Hash::default().bytes) - } -} - -impl Serialize for Hash { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where - S: Serializer { - serializer.serialize_str(&crate::utils::to_hex(&self.bytes)) - } -} - -struct HashVisitor; - -impl<'de> Visitor<'de> for HashVisitor { - type Value = Hash; - - fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> { - formatter.write_str("64 bytes") - } - - fn visit_bytes(self, v: &[u8]) -> Result where E: DeError, { - if v.len() == Hash::LEN { - let mut h = [0; Hash::LEN]; - let copy_size = min(v.len(), Hash::LEN); - h[..copy_size].copy_from_slice(&v[..copy_size]); - Ok(Hash::new(h)) - } else { - Err(E::custom("Hash must be 64 bytes!")) - } - } -} - -impl<'dd> Deserialize<'dd> for Hash { - fn deserialize(deserializer: D) -> Result>::Error> where - D: Deserializer<'dd> { - deserializer.deserialize_bytes(HashVisitor) - } -} - -impl PartialEq for Hash { - fn eq(&self, other: &Self) -> bool { - utils::same_hash(&self.bytes, &other.bytes) - } - - fn ne(&self, other: &Self) -> bool { - !utils::same_hash(&self.bytes, &other.bytes) - } -} - -impl AsRef<[u8]> for Hash { - fn as_ref(&self) -> &[u8] { - &self.bytes - } -} - -impl fmt::Debug for Hash { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let hash_hex = self.to_hex(); - const NUM_SHOW: usize = 8; - - write!(f, "{}", &hash_hex[..NUM_SHOW]) - } -} - -impl Default for Hash { - fn default() -> Hash { - ZERO_HASH - } -} \ No newline at end of file diff --git a/src/keys.rs b/src/keys.rs index cde06bb..24728e2 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -5,14 +5,16 @@ use rand::{thread_rng, Rng}; use std::fs; use std::fmt; use std::path::Path; -use std::io::Error as IoError; use serde::export::fmt::Error; use serde::{Serialize, Deserialize, Serializer, Deserializer}; +// For deserialization +use serde::de::{Error as DeError, Visitor}; +use serde::export::Formatter; -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Signature { - private_key: KeyPrivate, - public_key: KeyPublic, + private_key: Key, + public_key: Key, } impl Signature { @@ -21,12 +23,12 @@ impl Signature { let mut rng = thread_rng(); rng.fill(&mut buf); let (private, public) = keypair(&buf); - Signature {private_key: KeyPrivate::new(&private), public_key: KeyPublic::new(&public)} + Signature {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public)} } pub fn from_bytes(seed: &[u8]) -> Self { let (private, public) = keypair(&seed); - Signature {private_key: KeyPrivate::new(&private), public_key: KeyPublic::new(&public)} + Signature {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public)} } pub fn from_file(filename: &str, _password: &str) -> Option { @@ -40,11 +42,11 @@ impl Signature { } } - pub fn get_public(&self) -> KeyPublic { + pub fn get_public(&self) -> Key { self.public_key.clone() } - pub fn get_private(&self) -> KeyPrivate { + pub fn get_private(&self) -> Key { self.private_key.clone() } @@ -53,37 +55,53 @@ impl Signature { } pub fn check(&self, message: &[u8], public_key: &[u8], signature: &[u8]) -> bool { - verify(message, &self.public_key.data, signature) + verify(message, public_key, signature) } } -/*impl fmt::Debug for Signature { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("Signature") - .field("pub", &&self.public_key[..]) - .field("priv", &&self.private_key[..]) - .finish() - } -}*/ - -#[derive(Clone, Copy)] -pub struct KeyPublic { - data: [u8; 32] +#[derive(Clone)] +pub struct Key { + data: Vec } -impl KeyPublic { - pub fn new(data: &[u8]) -> Self { - let mut buf = [0u8; 32]; - buf.copy_from_slice(data); - KeyPublic{ data: buf } +impl Key { + pub fn new(data: Vec) -> Self { + Key { data } + } + + pub fn from_bytes(data: &[u8]) -> Self { + Key { data: Vec::from(data) } } pub fn length(&self) -> usize { self.data.len() } + + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + /// Returns a byte slice of the hash contents. + pub fn as_bytes(&self) -> &[u8] { + &self.data + } + + pub fn zero32() -> Self { + Key { data: [0u8; 32].to_vec() } + } + + pub fn zero64() -> Self { + Key { data: [0u8; 64].to_vec() } + } } -impl PartialEq for KeyPublic { +impl Default for Key { + fn default() -> Key { + Key { data: Vec::new() } + } +} + +impl PartialEq for Key { fn eq(&self, other: &Self) -> bool { crate::utils::same_hash(&self.data, &other.data) } @@ -93,112 +111,47 @@ impl PartialEq for KeyPublic { } } -impl fmt::Debug for KeyPublic { +impl fmt::Debug for Key { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(&crate::utils::to_hex(&self.data)) } } -impl Serialize for KeyPublic { +impl Serialize for Key { fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where S: Serializer { serializer.serialize_str(&crate::utils::to_hex(&self.data)) } } -#[derive(Clone, Copy)] -pub struct KeyPrivate { - data: [u8; 64] -} +struct KeyVisitor; -impl KeyPrivate { - pub fn new(data: &[u8]) -> Self { - let mut buf = [0u8; 64]; - buf.copy_from_slice(data); - KeyPrivate{ data: buf } - } - - pub fn length(&self) -> usize { - self.data.len() - } -} - -impl PartialEq for KeyPrivate { - fn eq(&self, other: &Self) -> bool { - crate::utils::same_hash(&self.data, &other.data) - } - - fn ne(&self, other: &Self) -> bool { - !crate::utils::same_hash(&self.data, &other.data) - } -} - -impl fmt::Debug for KeyPrivate { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(&crate::utils::to_hex(&self.data)) - } -} - -impl Serialize for KeyPrivate { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where - S: Serializer { - serializer.serialize_str(&crate::utils::to_hex(&self.data)) - } -} - -use serde::de::{Error as DeError, Visitor}; -use serde::export::Formatter; - -struct PublicVisitor; - -impl<'de> Visitor<'de> for PublicVisitor { - type Value = KeyPublic; +impl<'de> Visitor<'de> for KeyVisitor { + type Value = Key; fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> { - formatter.write_str("32 bytes") + formatter.write_str("32 or 64 bytes") } - fn visit_bytes(self, v: &[u8]) -> Result where E: DeError, { - if v.len() == 32 { - let mut h = [0; 32]; - h[..32].copy_from_slice(&v[..32]); - Ok(KeyPublic::new(&h)) + fn visit_str(self, value: &str) -> Result where E: DeError, { + if value.len() == 64 || value.len() == 128 { + Ok(Key::new(crate::from_hex(value).unwrap())) } else { - Err(E::custom("KeyPublic must be 32 bytes!")) + Err(E::custom("Key must be 32 or 64 bytes!")) + } + } + + fn visit_bytes(self, value: &[u8]) -> Result where E: DeError, { + if value.len() == 32 || value.len() == 64 { + Ok(Key::from_bytes(value)) + } else { + Err(E::custom("Key must be 32 or 64 bytes!")) } } } -impl<'dd> Deserialize<'dd> for KeyPublic { - fn deserialize(deserializer: D) -> Result>::Error> where - D: Deserializer<'dd> { - deserializer.deserialize_bytes(PublicVisitor) - } -} - -struct PrivateVisitor; - -impl<'de> Visitor<'de> for PrivateVisitor { - type Value = KeyPrivate; - - fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> { - formatter.write_str("32 bytes") - } - - fn visit_bytes(self, v: &[u8]) -> Result where E: DeError, { - if v.len() == 64 { - let mut h = [0; 64]; - h[..64].copy_from_slice(&v[..64]); - Ok(KeyPrivate::new(&h)) - } else { - Err(E::custom("KeyPrivate must be 64 bytes!")) - } - } -} - -impl<'dd> Deserialize<'dd> for KeyPrivate { - fn deserialize(deserializer: D) -> Result>::Error> where - D: Deserializer<'dd> { - deserializer.deserialize_bytes(PrivateVisitor) +impl<'dd> Deserialize<'dd> for Key { + fn deserialize(deserializer: D) -> Result>::Error> where D: Deserializer<'dd> { + deserializer.deserialize_str(KeyVisitor) } } diff --git a/src/lib.rs b/src/lib.rs index 391a526..a08d7a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,10 @@ pub use crate::block::Block; mod blockchain; pub use crate::blockchain::Blockchain; pub mod transaction; +pub use crate::transaction::Action; pub use crate::transaction::Transaction; pub mod utils; pub use crate::utils::*; -pub mod hash; -pub use crate::hash::Hash; pub mod keys; -pub use crate::keys::Signature; \ No newline at end of file +pub use crate::keys::Signature; +pub use crate::keys::Key; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index bfd715e..1463484 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ -use Wyrd::{Blockchain, Block, Transaction, Signature, Hash}; -use Wyrd::transaction::Action; +use wyrd_ns::{Blockchain, Block, Action, Transaction, Signature, Key}; fn main() { println!("Wyrd DNS 0.1.0"); @@ -17,7 +16,7 @@ fn test_blockchain() -> () { // Signing it with private key from Signature let sign_hash = signature.sign(&transaction.get_bytes()); - transaction.set_signature(Hash::new(sign_hash)); + transaction.set_signature(Key::from_bytes(&sign_hash)); // Creating a block with that signed transaction let mut block = blockchain.new_block(transaction); @@ -31,6 +30,9 @@ fn test_blockchain() -> () { blockchain.add_block(block); println!("Second block added"); + let block2: Block = serde_json::from_str(&s).unwrap(); + println!("DeSerialized block:\n{:?}", block2); + // Let's check if the blockchain is valid if blockchain.check() { println!("Blockchain is correct"); diff --git a/src/transaction.rs b/src/transaction.rs index 4f067b5..f6457a3 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,4 +1,3 @@ -use super::*; use crate::transaction::Action::{MoveDomain, RenewDomain, ChangeDomain, NewDomain}; use crate::keys::*; extern crate serde; @@ -7,15 +6,14 @@ extern crate serde_json; use serde::{Serialize, Deserialize, Serializer}; use serde::ser::SerializeStruct; use std::fmt; -use crypto::util::fixed_time_eq; #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(tag = "type")] pub enum Action { - NewDomain { name: String, owner: KeyPublic, #[serde(skip_serializing_if = "Vec::is_empty")] records: Vec, #[serde(skip_serializing_if = "Vec::is_empty")] tags: Vec, days: u16 }, + NewDomain { name: String, owner: Key, #[serde(default, skip_serializing_if = "Vec::is_empty")] records: Vec, #[serde(default, skip_serializing_if = "Vec::is_empty")] tags: Vec, days: u16 }, ChangeDomain { name: String, records: Vec, tags: Vec }, RenewDomain { name: String, days: u16 }, - MoveDomain { name: String, new_owner: KeyPublic }, + MoveDomain { name: String, new_owner: Key }, } impl Action { @@ -32,7 +30,7 @@ impl Action { } pub fn move_domain(name: String, new_owner: [u8; 32]) -> Self { - MoveDomain {name, new_owner: KeyPublic::new(&new_owner)} + MoveDomain {name, new_owner: Key::from_bytes(&new_owner)} } pub fn get_bytes(&self) -> Vec { @@ -84,16 +82,16 @@ impl fmt::Debug for Action { #[derive(Clone, Deserialize, PartialEq)] pub struct Transaction { pub action: Action, - pub pub_key: KeyPublic, - pub signature: Hash, + pub pub_key: Key, + pub signature: Key, } impl Transaction { - pub fn new(action: Action, pub_key: KeyPublic) -> Self { - Transaction {action, pub_key, signature: Hash::new([0u8; 64])} + pub fn new(action: Action, pub_key: Key) -> Self { + Transaction {action, pub_key, signature: Key::zero64()} } - pub fn set_signature(&mut self, hash: Hash) { + pub fn set_signature(&mut self, hash: Key) { self.signature = hash; } @@ -106,6 +104,7 @@ impl Transaction { impl fmt::Debug for Transaction { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Transaction") + .field("action", &self.action) .field("pub", &&self.pub_key) .field("sign", &&self.signature) .finish() diff --git a/src/utils.rs b/src/utils.rs index d90db3f..928ca20 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,4 @@ +use std::num; /// Convert bytes array to HEX format pub fn to_hex(buf: &[u8]) -> String { @@ -8,6 +9,19 @@ pub fn to_hex(buf: &[u8]) -> String { result } +pub fn from_hex(string: &str) -> Result, num::ParseIntError> { + split_n(&string.trim()[..], 2) + .iter() + .map(|b| u8::from_str_radix(b, 16)) + .collect() +} + +fn split_n(s: &str, n: usize) -> Vec<&str> { + (0..=(s.len() - n + 1) / 2) + .map(|i| &s[2 * i..2 * i + n]) + .collect() +} + /// There is no default PartialEq implementation for arrays > 32 in size pub fn same_hash(left: &[u8], right: &[u8]) -> bool { for (x, y) in left.iter().zip(right) {