variable salt and init pow

This commit is contained in:
Aravinth Manivannan 2021-03-06 16:43:20 +05:30
parent 01755af3d4
commit 2a23e064e1
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
3 changed files with 161 additions and 43 deletions

81
Cargo.lock generated
View file

@ -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"

View file

@ -17,3 +17,4 @@ categories = ["algorithms", "cryptography::cryptocurrencies"]
sha2 = "0.9"
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3"
derive_builder = "0.9"

View file

@ -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<T> {
pub nonce: u64,
pub result: String,
#[builder(default = "PhantomData", setter(skip))]
_spook: PhantomData<T>,
}
impl<T: Serialize> PoW<T> {
/// 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<PoW<T>> {
bincode::serialize(t).map(|v| Self::prove_work_serialized(&v, difficulty))
pub fn prove_work<T>(&self, t: &T, difficulty: u128) -> bincode::Result<PoW<T>>
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<T: Serialize> PoW<T> {
///
/// 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<T> {
let prefix_sha = Sha256::new().chain(SALT).chain(prefix);
pub fn prove_work_serialized<T>(&self, prefix: &[u8], difficulty: u128) -> PoW<T>
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<T: Serialize> PoW<T> {
}
/// Calculate the PoW score with the provided input T.
pub fn calculate(&self, t: &T) -> bincode::Result<u128> {
bincode::serialize(t).map(|v| self.calculate_serialized(&v))
pub fn calculate<T>(&self, pow: &PoW<T>, t: &T) -> bincode::Result<u128>
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<T>(&self, pow: &PoW<T>, 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<T>(&self, pow: &PoW<T>, 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<T: Serialize> PoW<T> {
}
/// Checks if the PoW result is of sufficient difficulty
pub fn is_sufficient_difficulty(&self, target_diff: u128) -> bool {
match self.result.parse::<u128>() {
pub fn is_sufficient_difficulty<T>(&self, pow: &PoW<T>, target_diff: u128) -> bool
where
T: Serialize,
{
match pow.result.parse::<u128>() {
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<String>> = 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<u8>) = (target, pw);
let message_ser = bincode::serialize(&message).unwrap();
let recieved_message: (u8, PoW<u8>) = 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));
}
}