examples, doc and readme update

This commit is contained in:
Aravinth Manivannan 2021-03-06 17:07:28 +05:30
parent 2a23e064e1
commit 0bfbce0185
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
4 changed files with 111 additions and 49 deletions

View file

@ -1,16 +1,16 @@
[package] [package]
name = "pow_sha256" name = "pow_sha256"
version = "0.1.0" version = "0.1.0"
authors = ["Robert Kornacki <robk@syre.io>, Aravinth Manivannan <realaravinth@bastsense.net>"] authors = [ "Aravinth Manivannan <realaravinth@bastsense.net>", "Robert Kornacki <robk@syre.io>"]
description = """ description = """
SHA256 PoW on any serializable datatype. SHA256 PoW on any serializable datatype used in mCaptcha
""" """
edition = "2018" edition = "2018"
keywords = ["PoW", "sha256", "proof-of-work"] keywords = ["mCaptcha", "PoW", "sha256", "proof-of-work"]
readme = "readme.md" readme = "README.md"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/mcaptcha/pow_sha256" repository = "https://github.com/mcaptcha/pow_sha256"
categories = ["algorithms", "cryptography::cryptocurrencies"] categories = ["captcha", "algorithms", "cryptography::cryptocurrencies"]
[dependencies] [dependencies]

View file

@ -1,9 +1,7 @@
<div align="center"> <div align="center">
<h1>PoW_SHA256</h1> <h1>PoW-SHA256</h1>
<p> <p>
<strong>PoW_SHA256 - SHA256 based Proof-of-Work</strong> <strong>PoW-SHA256 - SHA256 based Proof-of-Work</strong>
</p> </p>
[![Documentation](https://img.shields.io/badge/docs-master-blue)](https://mcaptcha.github.io/pow_sha256/pow_sha256/index.html) [![Documentation](https://img.shields.io/badge/docs-master-blue)](https://mcaptcha.github.io/pow_sha256/pow_sha256/index.html)
@ -26,36 +24,39 @@ crate can be used to prove work was done on a given serializable input.
The input merely needs to implement `serde::Deserialize` to be used. The input merely needs to implement `serde::Deserialize` to be used.
This is a fork of the [`pow` library](https://github.com/bddap/pow) by This is a fork of the [`pow` library](https://github.com/bddap/pow) by
bddap with some new additions. Primary of these being: [@robkorn](https://github.com/robkorn/pow_sha256)) with some new
additions. Primary of these being:
- PoW datatype now saves the calculation result to be used for checking - PoW datatype now offers a constructor
proof validity given input - Salt is no longer hard coded into the library, users can provide
- `is_valid_proof` method to do the above mentioned unique salts.
- PoW datatype no longer saves `u128` values as these are unsupported by
popular serialization formats (CBOR, Msgpack, ...)
- `is_sufficient_difficulty` method to check difficulty with new changes
Other small changes have also been included of various importance but Other small changes have also been included of various importance but
mostly just stylistic/ease of use improvements. mostly just stylistic/ease of use improvements.
# Examples ## Examples
Prove work was done, specifically targeting a phrase. Prove work specifically targeting a phrase.
```rust ```rust
use pow_sha256::PoW;
// Very easy difficulty use pow_sha256::{ConfigBuilder, PoW};
let difficulty = u128::max_value() - u128::max_value() / 2;
let phrase = b"Phrase to be used.".to_vec(); fn main() {
let pw = PoW::prove_work(&phrase, difficulty).unwrap(); let config = ConfigBuilder::default()
.salt("myrandomsaltisnotlongenoug".into())
.build()
.unwrap();
// Asserting that the result is of sufficient difficulty let phrase = "ironmansucks";
assert!(pw.is_sufficient_difficulty(difficulty));
// Asserting that the PoW was generated from the provided phrase const DIFFICULTY: u128 = u128::MAX / 32;
assert!(pw.is_valid_proof(&phrase))
let work = config.prove_work(&phrase, DIFFICULTY).unwrap();
assert!(config.calculate(&work, &phrase).unwrap() >= DIFFICULTY);
assert!(config.is_valid_proof(&work, &phrase));
assert!(config.is_sufficient_difficulty(&work, DIFFICULTY));
}
``` ```
Prove more difficult work. This time targeting a time. Prove more difficult work. This time targeting a time.
@ -63,22 +64,36 @@ Prove more difficult work. This time targeting a time.
```rust ```rust
// Greater difficulty this time around. Takes around 100,000 hashes // Greater difficulty this time around. Takes around 100,000 hashes
// to find a nonce of the correct difficulty. // to find a nonce of the correct difficulty.
let difficulty = u128::max_value() - u128::max_value() / 100_000;
let now: u64 = get_unix_time_seconds();
let pw = PoW::prove_work(&now, difficulty).unwrap();
assert!(pw.is_sufficient_difficulty(difficulty)); use pow_sha256::{ConfigBuilder, PoW};
assert!(pw.is_valid_proof(&phrase))
fn main() {
let config = ConfigBuilder::default()
.salt("myrandomsaltisnotlongenoug".into())
.build()
.unwrap();
let phrase = "ironmansucks";
const DIFFICULTY: u128 = u128::max_value() - u128::max_value() / 100_000;
let work = config.prove_work(&phrase, DIFFICULTY).unwrap();
assert!(config.calculate(&work, &phrase).unwrap() >= DIFFICULTY);
assert!(config.is_valid_proof(&work, &phrase));
assert!(config.is_sufficient_difficulty(&work, DIFFICULTY));
}
``` ```
## Hashing Scheme
# Hashing Scheme `SALT` is used as prefix to prevent PoW reuse from other systems such as
proof of work blockchains.
A randomly generated constant, `SALT`, is used as prefix to prevent PoW
reuse from other systems such as proof of work blockchains.
SHA256 is calculated over the concatenation of the: SHA256 is calculated over the concatenation of the:
- SALT - SALT
- Serialized Input `T` - Serialized Input `T`
- Nonce - Nonce
@ -86,8 +101,7 @@ SHA256 is calculated over the concatenation of the:
The first 16 bytes of the resulting hash are interpreted as a 128 bit The first 16 bytes of the resulting hash are interpreted as a 128 bit
unsigned integer and saved as the final result. unsigned integer and saved as the final result.
## Choosing a difficulty setting.
# Choosing a difficulty setting.
Depending on your use case, difficulty settings often are best set Depending on your use case, difficulty settings often are best set
dynamically a la bitcoin. dynamically a la bitcoin.
@ -104,7 +118,8 @@ fn get_difficulty(average: u128) -> u128 {
} }
``` ```
Conversely we can use the same equation to calculate the probable number of hashes required to satisfy a given difficulty: Conversely we can use the same equation to calculate the probable number
of hashes required to satisfy a given difficulty:
```rust ```rust
fn est_average(difficulty: u128) -> u128 { fn est_average(difficulty: u128) -> u128 {

21
examples/simple.rs Normal file
View file

@ -0,0 +1,21 @@
/* The easiest way to use this crate is with the default configuration.
* See `Default` implementation for the default configuration.
*/
use pow_sha256::{ConfigBuilder, PoW};
fn main() {
let config = ConfigBuilder::default()
.salt("myrandomsaltisnotlongenoug".into())
.build()
.unwrap();
let phrase = "ironmansucks";
const DIFFICULTY: u128 = u128::MAX / 32;
let work = config.prove_work(&phrase, DIFFICULTY).unwrap();
assert!(config.calculate(&work, &phrase).unwrap() >= DIFFICULTY);
assert!(config.is_valid_proof(&work, &phrase));
assert!(config.is_sufficient_difficulty(&work, DIFFICULTY));
}

View file

@ -1,3 +1,26 @@
//! MCaptch's SHA256 based Proof of Work library
//!
//! # Example:
//! ```rust
//! use pow_sha256::{ConfigBuilder, PoW};
//!
//! fn main() {
//! let config = ConfigBuilder::default()
//! .salt("myrandomsaltisnotlongenoug".into())
//! .build()
//! .unwrap();
//!
//! let phrase = "ironmansucks";
//!
//! const DIFFICULTY: u128 = u128::MAX / 32;
//!
//! let work = config.prove_work(&phrase, DIFFICULTY).unwrap();
//! assert!(config.calculate(&work, &phrase).unwrap() >= DIFFICULTY);
//! assert!(config.is_valid_proof(&work, &phrase));
//! assert!(config.is_sufficient_difficulty(&work, DIFFICULTY));
//! }
//! ```
use std::marker::PhantomData; use std::marker::PhantomData;
use derive_builder::Builder; use derive_builder::Builder;
@ -13,7 +36,10 @@ pub struct PoW<T> {
_spook: PhantomData<T>, _spook: PhantomData<T>,
} }
/// Proof of Work over concrete type T. T can be any type that implements serde::Serialize. /// Configuration for generting proof of work
/// Please choose a long, unique value for salt
/// Resistance to dictionary/rainbow attacks depend on uniqueness
/// of the salt
#[derive(Serialize, Deserialize, Builder, PartialEq, Clone, Debug)] #[derive(Serialize, Deserialize, Builder, PartialEq, Clone, Debug)]
pub struct Config { pub struct Config {
pub salt: String, pub salt: String,
@ -22,8 +48,8 @@ pub struct Config {
impl Config { impl Config {
/// Create Proof of Work over item of type T. /// 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 /// Make sure difficulty is not too high. A 64 bit difficulty,
/// on a general purpose processor. /// for example, takes a long time on a general purpose processor.
/// Returns bincode::Error if serialization fails. /// Returns bincode::Error if serialization fails.
pub fn prove_work<T>(&self, t: &T, difficulty: u128) -> bincode::Result<PoW<T>> pub fn prove_work<T>(&self, t: &T, difficulty: u128) -> bincode::Result<PoW<T>>
where where
@ -35,8 +61,8 @@ impl Config {
/// Create Proof of Work on an already serialized item of type T. /// Create Proof of Work on an already serialized item of type T.
/// The input is assumed to be serialized using network byte order. /// The input is assumed to be serialized using network byte order.
/// ///
/// Make sure difficulty is not too high. A 64 bit difficulty, for example, takes a long time /// Make sure difficulty is not too high. A 64 bit difficulty,
/// on a general purpose processor. /// for example, takes a long time on a general purpose processor.
pub fn prove_work_serialized<T>(&self, prefix: &[u8], difficulty: u128) -> PoW<T> pub fn prove_work_serialized<T>(&self, prefix: &[u8], difficulty: u128) -> PoW<T>
where where
T: Serialize, T: Serialize,