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
//! 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.
//!
//! ```
//! 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.
//!
//! ```
//! # 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);
//! ```

//! # 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:
//!
//! ```
//! # 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
//! derterministic 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.
//!
//! ```
//! 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.
//!
//! 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;