Andrew Dirksen 2019-05-13 10:10:19 -07:00
parent 86a7d9bfcb
commit cd7b218e51
3 changed files with 88 additions and 5 deletions

View file

@ -1,15 +1,17 @@
[package] [package]
name = "pow" name = "pow"
version = "0.1.2" version = "0.1.3"
authors = ["Andrew Dirksen <andrew@dirksen.com>"] authors = ["Andrew Dirksen <andrew@dirksen.com>"]
description = """ description = """
Generate or verify sha256 based proofs of work over arbitrary typed data. Generate or verify sha256 based proofs of work over arbitrary typed data.
""" """
edition = "2018" edition = "2018"
documentation = "https://docs.rs/pow" documentation = "https://docs.rs/pow"
tags = ["proof of work", "pw set", "powtag", "tag"] keywords = ["pwset", "powtag", "tag"]
readme = "readme.md" readme = "readme.md"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/bddap/pow"
categories = [] # pr me!
[dependencies] [dependencies]
sha2 = "0.8.0" sha2 = "0.8.0"

View file

@ -1,5 +1,86 @@
# Pow # Pow
Typed proof of work tags. Sha256 based proof of work over a typed piece of data.
[docs](https://docs.rs/pow) 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.
```
// 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:
```
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.
```
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)
}
```

View file

@ -63,7 +63,7 @@
//! # Serialization encoding. //! # Serialization encoding.
//! //!
//! It shouldn't matter to users of this library, but the bincode crate is used for cheap //! 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. //! deterministic serialization. All values are serialized using network byte order.
//! //!
//! # Threshold scheme //! # Threshold scheme
//! //!