pow_sha256/README.md
2019-07-22 17:13:00 -04:00

2.8 KiB

PoW_SHA256

Rust crate which generates SHA256 Proofs of Work on serializable datatypes.

Whether for blockchain-related projects or Hashcash-like schemes, this 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.

This is a fork of the pow library by bddap with some new additions. Primary of these being:

  • PoW datatype now saves the calculation result to be used for checking proof validity given input
  • is_valid_proof method to do the above mentioned

Other small changes have also been included of various importance but mostly just stylistic/ease of use improvements.

Examples

Prove work was done, specifically targeting a phrase.

use PoW_SHA256::PoW;

// Very easy difficulty
let difficulty = u128::max_value() - u128::max_value() / 2;

let phrase = b"Phrase to be used.".to_vec();
let pw = PoW::prove_work(&phrase, difficulty).unwrap();

// Asserting that the result is of sufficient difficulty
assert!(pw.result >= difficulty);

// Asserting that the PoW was generated from the provided phrase
assert!(pw.is_valid_proof(&phrase))

Prove more difficult work. This time targeting a time.

// Greater diffculty this time around. Takes around 100,000 hashes 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.result >= difficulty);
assert!(pw.is_valid_proof(&phrase))

Hashing Scheme

SHA256 is calculated over the concatenation of the:

  • SALT
  • Serialized Input T
  • Nonce

The first 16 bytes of the resulting hash are interpreted as a 128 bit unsigned integer.

A randomly generated constant, SALT, is used as prefix to prevent PoW reuse from other systems such as proof of work blockchains.

Choosing a difficulty setting.

Depending on your use case, difficulty settings often are best set dynamically a la bitcoin.

However if your use case requires manual setting then it is trivial to set one yourself. One way to manually select a difficulty is to choose the average Hnumber of hashes desired with a function like this:

fn get_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 we can use the same equation to calculate the probable number of hashes required to satisfy a given difficulty:

fn est_average(difficulty: u128) -> u128 {
    let m = u128::max_value();
    if difficulty == m {
        return m;
    } 
    m / (m - difficulty)
}

License

This project is dual-licensed under Apache License Version 2.0 & MIT license.