1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Sha256 based proof of work over a typed piece of data.
//!
//! Any type that implementes serde::Deserialize can be tagged with a proof of work.
//!
//! # Examples
//!
//! Prove we did work targeting a phrase.
//!
//! ```rust
//! use pow::Pow;
//!
//! // very easy mode
//! let difficulty = u128::max_value() - u128::max_value() / 2;
//!
//! let phrase = b"Phrase to tag.".to_vec();
//! let pw = Pow::prove_work(&phrase, difficulty).unwrap();
//! assert!(pw.score(&phrase).unwrap() >= difficulty);
//! ```
//!
//! Prove more difficult work. This time targeting a time.
//!
//! ```rust
//! # fn get_unix_time_seconds() -> u64 {
//! #     use std::time::{Duration, SystemTime};
//! #     SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs()
//! # }
//! # use pow::Pow;
//!
//! // more diffcult, takes around 100_000 hashes to generate proof
//! 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.score(&now).unwrap() >= difficulty);
//! ```
//!
//! Define a blockchain block.
//!
//! ```rust
//! # use pow::Pow;
//! struct Block<T> {
//!     prev: [u8; 32], // hash of last block
//!     payload: T,     // generic data
//!     proof_of_work: Pow<([u8; 32], T)>,
//! }
//! ```
//!
//! # Score scheme
//!
//! To score a proof of work for a given (target, Pow) pair:
//! Sha256 is calculated over the concatenation SALT + target + Pow.
//! The first 16 bytes of the hash are interpreted as a 128 bit unsigned integer.
//! That integer is the score.
//! A constant, SALT, is used as prefix to prevent pow reuse from other systems such as proof
//! of work blockchains.
//!
//! In other words:
//!
//! ```rust
//! # use serde::Serialize;
//! # use pow::Pow;
//! # use core::any::Any;
//! # const SALT: &'static str = "not the actual salt used";
//! # fn serialize<T: Serialize>(_: &T) -> u8 { 0 } // not the actual serialize function
//! # fn deserialize(_: &[u8]) -> u128 { 0 } // not the actual deserialize function
//! # fn sha256(_: &u8) -> [u8; 32] { [0; 32] } // not the actual sha256 function
//! fn score<T: Serialize>(target: &T, pow_tag: &Pow<T>) -> u128 {
//!     let bytes = serialize(&SALT) + serialize(target) + serialize(pow_tag);
//!     let hash = sha256(&bytes);
//!     deserialize(&hash[..16])
//! }
//! ```
//!
//! # Serialization encoding.
//!
//! It shouldn't matter to users of this library, but the bincode crate is used for cheap
//! deterministic serialization. All values are serialized using network byte order.
//!
//! # Threshold scheme
//!
//! Given a minimum score m. A Pow p satisfies the minimum score for target t iff score(t, p) >= m.
//!
//! # Choosing a difficulty setting.
//!
//! Difficulty settings are usually best adjusted dynamically a la bitcoin.
//!
//! To manually select a difficulty, choose the average number of hashes required.
//!
//! ```rust
//! fn difficulty(average: u128) -> u128 {
//!     debug_assert_ne!(average, 0, "It is impossible to prove work in zero attempts.");
//!     let m = u128::max_value();
//!     m - m / average
//! }
//! ```
//!
//! Conversely, to calculate probable number of hashes required to satisfy a given minimum
//! difficulty.
//!
//! ```rust
//! fn average(difficulty: u128) -> u128 {
//!     let m = u128::max_value();
//!     if difficulty == m {
//!         return m;
//!     }
//!     m / (m - difficulty)
//! }
//! ```

mod proof_of_work;

pub use proof_of_work::Pow;