This commit is contained in:
Andrew Dirksen 2019-05-10 14:28:06 -07:00
parent 8b045cf61c
commit 69e75e116c
3 changed files with 77 additions and 6 deletions

View file

@ -1,11 +1,14 @@
[package]
name = "pow"
version = "0.1.0"
version = "0.1.1"
authors = ["Andrew Dirksen <andrew@dirksen.com>"]
description = """
Tag arbitrary data types with proof of work based on sha256.
Generate or verify sha256 based proofs of work over arbitrary typed data.
"""
edition = "2018"
documentation = "https://docs.rs/pow"
tags = ["proof of work", "pw set", "powtag", "tag"]
readme = "readme.md"
license = "MIT OR Apache-2.0"
[dependencies]

5
readme.md Normal file
View file

@ -0,0 +1,5 @@
# Pow
Typed proof of work tags.
[docs](https://docs.rs/pow)

View file

@ -8,7 +8,10 @@
//!
//! ```
//! use pow::Pow;
//! let difficulty = u128::max_value() / 2; // very easy mode
//!
//! // 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);
@ -22,14 +25,74 @@
//! # SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs()
//! # }
//! # use pow::Pow;
//! let difficulty = u128::max_value() / 10_000 * 9_999; // more diffcult, around 10_000 hashes
//!
//! // 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);
//! ```
//! Expected computional cost scales something like
//! O(u128::max_value() / (u128::max_value() - 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;