RSPOW
A simple multi-algorithm proof-of-work library for Rust.
Algorithms
- SHA-256
- SHA-512
- RIPEMD-320
- Scrypt
- Argon2id
API references are available at docs.rs/rspow.
Difficulty Modes
RSPOW supports two difficulty modes:
- AsciiZeroPrefix (default): the hash must start with
difficultybytes of ASCII'0'(0x30).- Expected attempts grow by ~256 per additional byte.
- Simple to explain, but coarse-grained and often too steep for memory-hard hashes.
- LeadingZeroBits: the hash must have at least
difficultyleading zero bits.- Expected attempts ≈
2^difficulty. - Fine-grained control suitable for tuning across a wide range.
- Expected attempts ≈
Notes:
PoW::calculate_target()returns the ASCII'0'prefix and is meaningful only forAsciiZeroPrefix.- In
LeadingZeroBitsmode, thetargetslice is ignored; pass an empty slice for clarity.
Examples
ASCII '0' prefix (default)
use ;
let data = "hello world";
let difficulty = 2; // requires prefix "00"
let algorithm = Sha2_512;
let pow = new.unwrap;
let target = pow.calculate_target; // [0x30; difficulty]
let = pow.calculate_pow;
assert!;
assert!;
Leading zero bits (fine-grained)
use ;
let data = "hello world";
let bits = 12; // expected attempts ~ 2^12 = 4096
let algorithm = Sha2_256;
let pow = with_mode.unwrap;
let = pow.calculate_pow; // target is ignored in bits mode
assert!;
assert!;
Argon2id with custom parameters
use ;
let data = b"hello world";
// Example parameters only; tune for your threat model.
let params = new.unwrap;
let algorithm = Argon2id;
// Prefer LeadingZeroBits for smoother tuning with memory-hard functions
let bits = 8; // expected attempts ~ 256
let pow = with_mode.unwrap;
let = pow.calculate_pow;
assert!;
Benchmarking
CLI benchmark (Argon2id, leading zero bits)
The crate ships an example that measures Argon2id proof-of-work time across bit difficulties with configurable parameters.
cargo run --release --example bench_argon2_leading_bits -- \
--start-bits 1 --max-bits 12 --repeats 5 \
--m-mib 128 --t-cost 3 --p-cost 1 \
--data "hello world"
- Results stream as CSV: each run emits a
runrow immediately, followed by asummaryrow per difficulty. --random-start=true(default) draws a random starting nonce for every repetition so that tries follow the expected geometric distribution. Disable with--random-start falseif you only want runtime variation.--seed <u64>fixes the random sequence for reproducibility.- Additional options:
--m-kib,--repeats,--start-bits,--max-bits,--data. Run with--helpfor the full list.
WASM build & browser demo
Use the helper script to drive formatting/tests, build the wasm bundle, and (optionally) launch a local server:
./scripts/wasm_pipeline.sh --offline --serve --port 8080
Flags:
--offlinekeeps Cargo/wasm-pack from hitting the network (CARGO_NET_OFFLINE=1).--devswitches to debug profile (default is release).--skip-testskipscargo test.--servelaunchespython3 -m http.serverinsidewasm-demo/www.
After the script completes, open http://127.0.0.1:8080 (or your chosen port). The browser UI lets you configure start/max bits, repeats, Argon2 parameters, and whether to randomize the nonce. Results append to the textarea as CSV and include mean, standard deviation, standard error, plus 95% and 99% confidence intervals for both time (ms) and tries.
KPoW (k-of-puzzles) — concurrent PoW with predictable wall time
KPoW lets you solve k independent puzzles concurrently with a worker pool of size workers (alpha), collecting the first k successes. This keeps verification cheap (≈ one Argon2 per proof) while improving wall‑time predictability (variance ~ 1/√k) and utilizing multiple cores.
- Library API
use ;
use Argon2Params;
let bits = 5; // compute/verify ≈ 2^bits = 32x
let params = new?; // 64MiB, t=3, p=1
let workers = 4;
let seed = ;
let payload = b"ctx".to_vec;
let kpow = new;
// Production: compute k proofs (no timing/tries overhead)
let proofs: = kpow.solve_proofs?;
assert!;
// Benchmarking: compute proofs and get total stats
let = kpow.solve_proofs_with_stats?;
println!;
- Demo example
cargo run --release --example kpow_demo
# Environment overrides (optional):
# KPOW_WORKERS=<usize> number of worker threads (default 4)
# KPOW_K=<usize> number of proofs to collect (default 8)
- KPoW benchmark example (CSV streaming + summary)
cargo run --release --example kpow_bench_argon2_leading_bits -- \
--bits 5 --k 8 --workers 4 --repeats 10 \
--m-mib 64 --t-cost 3 --p-cost 1 --payload demo | tee kpow_64mib.csv
Notes:
- Compute/verify ratio is governed by
bits: ≈2^bits(independent of Argon2 params). Withbits=5, ratio ≈ 32x. - Wall‑time predictability improves with
k(roughly ~ 1/√k). Verification cost grows linearly withk(≈kArgon2 runs). m_kib/t_cost/p_costdecide the per‑hash costc. Larger memory or t_cost increasescroughly linearly.
WASM (browser) threading quick note
To use KPoW with true threads in the browser (std::thread over Web Workers):
- Build with target features
+atomics,+bulk-memory,+mutable-globalsforwasm32-unknown-unknown. - Serve pages under cross‑origin isolation (COOP: same-origin, COEP: require-corp) so SharedArrayBuffer is enabled.
- This crate enforces threaded‑WASM by default; single‑thread fallback on wasm32 is only allowed if you explicitly build with
--cfg kpow_allow_single_thread.
Tuning Guidance
- LeadingZeroBits: each additional bit doubles expected attempts; choose
bitsto match your time budget. - AsciiZeroPrefix: each additional byte multiplies attempts by ~256; easy but coarse.
- Memory-hard algorithms (e.g., Argon2id, Scrypt) may make multi-byte ASCII prefix targets impractical; prefer
LeadingZeroBits.
Compatibility
- Existing code using
PoW::newandcalculate_target()keeps the legacy behavior by default. - New code is encouraged to adopt
DifficultyMode::LeadingZeroBitsfor precise difficulty control.