examples, doc and readme update
This commit is contained in:
parent
2a23e064e1
commit
0bfbce0185
4 changed files with 111 additions and 49 deletions
10
Cargo.toml
10
Cargo.toml
|
@ -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]
|
||||||
|
|
93
README.md
93
README.md
|
@ -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)
|
||||||
|
@ -14,48 +12,51 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> pow_sha256's copy of `pow_sha256` by
|
> pow_sha256's copy of `pow_sha256` by
|
||||||
> [robkorn](https://github.com/robkorn/pow_sha256)
|
> [robkorn](https://github.com/robkorn/pow_sha256)
|
||||||
> which is a modified version of [`pow` library](https://github.com/bddap/pow).
|
> which is a modified version of [`pow` library](https://github.com/bddap/pow).
|
||||||
> All copyrights belong to the original authors.
|
> All copyrights belong to the original authors.
|
||||||
|
|
||||||
Rust crate which generates SHA256 Proofs of Work on serializable datatypes.
|
Rust crate which generates SHA256 Proofs of Work on serializable datatypes.
|
||||||
|
|
||||||
Whether for blockchain-related projects or Hashcash-like schemes, this
|
Whether for blockchain-related projects or Hashcash-like schemes, this
|
||||||
crate can be used to prove work was done on a given serializable input.
|
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,31 +64,44 @@ 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
|
||||||
|
|
||||||
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,14 +118,15 @@ 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 {
|
||||||
let m = u128::max_value();
|
let m = u128::max_value();
|
||||||
if difficulty == m {
|
if difficulty == m {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
m / (m - difficulty)
|
m / (m - difficulty)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
21
examples/simple.rs
Normal file
21
examples/simple.rs
Normal 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));
|
||||||
|
}
|
36
src/lib.rs
36
src/lib.rs
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue