From 2a23e064e13c2bd2700ca6c7a33ec6a2d511ecdc Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 6 Mar 2021 16:43:20 +0530 Subject: [PATCH] variable salt and init pow --- Cargo.lock | 81 ++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/lib.rs | 122 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 161 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f65169..3a3d9ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,66 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_builder" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" +dependencies = [ + "darling", + "derive_builder_core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.9.0" @@ -48,6 +108,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "generic-array" version = "0.14.4" @@ -58,6 +124,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -66,9 +138,10 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "pow_sha256" -version = "0.2.1" +version = "0.1.0" dependencies = [ "bincode", + "derive_builder", "serde", "sha2", ] @@ -124,6 +197,12 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + [[package]] name = "syn" version = "1.0.61" diff --git a/Cargo.toml b/Cargo.toml index 9d565e6..0c20946 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,4 @@ categories = ["algorithms", "cryptography::cryptocurrencies"] sha2 = "0.9" serde = { version = "1.0", features = ["derive"] } bincode = "1.3" +derive_builder = "0.9" diff --git a/src/lib.rs b/src/lib.rs index e58f129..75e5561 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,27 +1,35 @@ use std::marker::PhantomData; +use derive_builder::Builder; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -const SALT: &str = "79ziepia7vhjgviiwjhnend3ofjqocsi2winc4ptqhmkvcajihywxcizewvckg9h6gs4j83v9"; - /// Proof of Work over concrete type T. T can be any type that implements serde::Serialize. -#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] +#[derive(Serialize, Builder, Deserialize, PartialEq, Clone, Debug)] pub struct PoW { pub nonce: u64, pub result: String, + #[builder(default = "PhantomData", setter(skip))] _spook: PhantomData, } -impl PoW { +/// Proof of Work over concrete type T. T can be any type that implements serde::Serialize. +#[derive(Serialize, Deserialize, Builder, PartialEq, Clone, Debug)] +pub struct Config { + pub salt: String, +} + +impl Config { /// Create Proof of Work over item of type T. /// /// Make sure difficulty is not too high. A 64 bit difficulty, for example, takes a long time /// on a general purpose processor. - /// /// Returns bincode::Error if serialization fails. - pub fn prove_work(t: &T, difficulty: u128) -> bincode::Result> { - bincode::serialize(t).map(|v| Self::prove_work_serialized(&v, difficulty)) + pub fn prove_work(&self, t: &T, difficulty: u128) -> bincode::Result> + where + T: Serialize, + { + bincode::serialize(t).map(|v| self.prove_work_serialized(&v, difficulty)) } /// Create Proof of Work on an already serialized item of type T. @@ -29,8 +37,11 @@ impl PoW { /// /// Make sure difficulty is not too high. A 64 bit difficulty, for example, takes a long time /// on a general purpose processor. - pub fn prove_work_serialized(prefix: &[u8], difficulty: u128) -> PoW { - let prefix_sha = Sha256::new().chain(SALT).chain(prefix); + pub fn prove_work_serialized(&self, prefix: &[u8], difficulty: u128) -> PoW + where + T: Serialize, + { + let prefix_sha = Sha256::new().chain(&self.salt).chain(prefix); let mut n = 0; let mut result = 0; while result < difficulty { @@ -45,21 +56,30 @@ impl PoW { } /// Calculate the PoW score with the provided input T. - pub fn calculate(&self, t: &T) -> bincode::Result { - bincode::serialize(t).map(|v| self.calculate_serialized(&v)) + pub fn calculate(&self, pow: &PoW, t: &T) -> bincode::Result + where + T: Serialize, + { + bincode::serialize(t).map(|v| self.calculate_serialized(pow, &v)) } /// Calculate the PoW score of an already serialized T and self. /// The input is assumed to be serialized using network byte order. - pub fn calculate_serialized(&self, target: &[u8]) -> u128 { - score(Sha256::new().chain(SALT).chain(target), self.nonce) + pub fn calculate_serialized(&self, pow: &PoW, target: &[u8]) -> u128 + where + T: Serialize, + { + score(Sha256::new().chain(&self.salt).chain(target), pow.nonce) } /// Verifies that the PoW is indeed generated out of the phrase provided. - pub fn is_valid_proof(&self, t: &T) -> bool { - match self.calculate(t) { + pub fn is_valid_proof(&self, pow: &PoW, t: &T) -> bool + where + T: Serialize, + { + match self.calculate(pow, t) { Ok(res) => { - return if self.result == res.to_string() { + return if pow.result == res.to_string() { true } else { false @@ -70,8 +90,11 @@ impl PoW { } /// Checks if the PoW result is of sufficient difficulty - pub fn is_sufficient_difficulty(&self, target_diff: u128) -> bool { - match self.result.parse::() { + pub fn is_sufficient_difficulty(&self, pow: &PoW, target_diff: u128) -> bool + where + T: Serialize, + { + match pow.result.parse::() { Ok(res) => return res >= target_diff, Err(_) => return false, } @@ -94,59 +117,74 @@ fn first_bytes_as_u128(inp: &[u8]) -> u128 { bincode::deserialize(&inp).unwrap() } -//fn bincode_cfg() -> bincode::Config { -// let mut cfg = bincode::config(); -// cfg.big_endian(); -// cfg - #[cfg(test)] mod test { use super::*; const DIFFICULTY: u128 = 0xff000000000000000000000000000000; + fn get_config() -> Config { + ConfigBuilder::default() + .salt( + "79ziepia7vhjgviiwjhnend3ofjqocsi2winc4ptqhmkvcajihywxcizewvckg9h6gs4j83v9".into(), + ) + .build() + .unwrap() + } + #[test] fn base_functionality() { // Let's prove we did work targeting a phrase. let phrase = b"Ex nihilo nihil fit.".to_vec(); - let pw = PoW::prove_work(&phrase, DIFFICULTY).unwrap(); - assert!(pw.calculate(&phrase).unwrap() >= DIFFICULTY); - assert!(pw.is_valid_proof(&phrase)); - assert!(pw.is_sufficient_difficulty(DIFFICULTY)); + let config = get_config(); + let pw = config.prove_work(&phrase, DIFFICULTY).unwrap(); + assert!(config.calculate(&pw, &phrase).unwrap() >= DIFFICULTY); + assert!(config.is_valid_proof(&pw, &phrase)); + assert!(config.is_sufficient_difficulty(&pw, DIFFICULTY)); } #[test] fn double_pow() { let phrase = "Ex nihilo nihil fit.".to_owned(); - let pw = PoW::prove_work(&phrase, DIFFICULTY).unwrap(); - let pwpw: PoW> = PoW::prove_work(&pw, DIFFICULTY).unwrap(); - assert!(pw.calculate(&phrase).unwrap() >= DIFFICULTY); - assert!(pwpw.calculate(&pw).unwrap() >= DIFFICULTY); - assert!(pw.is_sufficient_difficulty(DIFFICULTY)); - assert!(pwpw.is_sufficient_difficulty(DIFFICULTY)); - assert!(pw.is_valid_proof(&phrase)); - assert!(pwpw.is_valid_proof(&pw)); + let config = get_config(); + + let pw = config.prove_work(&phrase, DIFFICULTY).unwrap(); + let pwpw = config.prove_work(&pw, DIFFICULTY).unwrap(); + + assert!(config.calculate(&pw, &phrase).unwrap() >= DIFFICULTY); + assert!(config.is_valid_proof(&pw, &phrase)); + assert!(config.is_sufficient_difficulty(&pw, DIFFICULTY)); + + assert!(config.calculate(&pwpw, &pw).unwrap() >= DIFFICULTY); + assert!(config.is_valid_proof(&pwpw, &pw)); + assert!(config.is_sufficient_difficulty(&pwpw, DIFFICULTY)); } #[test] fn is_not_valid_proof() { let phrase = "Ex nihilo nihil fit.".to_owned(); let phrase2 = "Omne quod movetur ab alio movetur.".to_owned(); - let pw = PoW::prove_work(&phrase, DIFFICULTY).unwrap(); - let pw2 = PoW::prove_work(&phrase2, DIFFICULTY).unwrap(); - assert!(!pw.is_valid_proof(&phrase2)); - assert!(!pw2.is_valid_proof(&phrase)); + + let config = get_config(); + let pw = config.prove_work(&phrase, DIFFICULTY).unwrap(); + + let pw2 = config.prove_work(&phrase2, DIFFICULTY).unwrap(); + + assert!(!config.is_valid_proof(&pw, &phrase2)); + assert!(!config.is_valid_proof(&pw2, &phrase)); } #[test] fn serialization_test() { let target: u8 = 1; - let pw = PoW::prove_work(&target, DIFFICULTY).unwrap(); + let config = get_config(); + let pw = config.prove_work(&target, DIFFICULTY).unwrap(); + let message: (u8, PoW) = (target, pw); let message_ser = bincode::serialize(&message).unwrap(); let recieved_message: (u8, PoW) = bincode::deserialize(&message_ser).unwrap(); assert_eq!(recieved_message, message); - assert!(message.1.is_sufficient_difficulty(DIFFICULTY)); - assert!(message.1.is_valid_proof(&target)); + assert!(config.is_sufficient_difficulty(&message.1, DIFFICULTY)); + assert!(config.is_valid_proof(&message.1, &target)); } }