Powex - Proof of Work Implementation in Elixir with Rust NIF
A high-performance Proof of Work implementation for Elixir using Rust NIFs (Native Implemented Functions). This library provides efficient SHA-256 based mining and validation capabilities with support for parallel processing.
Features
- ๐ High Performance: Rust implementation for CPU-intensive operations
- ๐ Parallel Processing: Multi-threaded mining support
- ๐ SHA-256 Hashing: Industry-standard cryptographic hashing
- โ Comprehensive Validation: Built-in nonce validation
- ๐ Flexible Difficulty: Configurable difficulty levels
- ๐งช Well Tested: Comprehensive test suite
Installation
Add powex to your list of dependencies in mix.exs:
def deps do
[
{:powex, "~> 0.1.2"}
]
endRequirements
- Elixir 1.14+
- Rust 1.70+ (for compilation)
- Erlang/OTP 25+
Usage
Basic Proof of Work Computation
# Compute a nonce for given data and difficulty
{:ok, nonce} = Powex.compute("transaction_data", 5)
# Validate the computed nonce
valid = Powex.valid?("transaction_data", nonce, 5)
# => trueParallel Processing
For better performance on multi-core systems:
# Use 4 threads for parallel computation
{:ok, nonce} = Powex.compute_parallel("blockchain_data", 6, 4)
# Validate the result
Powex.valid?("blockchain_data", nonce, 6)
# => trueHash Inspection
Get the actual hash for debugging or verification:
{:ok, hash} = Powex.get_hash("data", 12345)
# => {:ok, "a1b2c3d4e5f6..."}API Reference
Powex.compute/2
Computes a Proof of Work nonce for the given data and difficulty.
Parameters:
data(binary): The input data to hashdifficulty(integer): Number of leading zeros required (0-64)
Returns:
{:ok, nonce}- Valid nonce found{:error, reason}- Computation failed
Powex.valid?/3
Validates if a nonce produces a valid Proof of Work.
Parameters:
data(binary): The input datanonce(integer): The nonce to validatedifficulty(integer): Required difficulty level
Returns:
true- Nonce is validfalse- Nonce is invalid
Powex.compute_parallel/3
Parallel Proof of Work computation using multiple threads.
Parameters:
data(binary): The input data to hashdifficulty(integer): Number of leading zeros requiredthreads(integer): Number of threads to use (1-64)
Returns:
{:ok, nonce}- Valid nonce found{:error, reason}- Computation failed
Powex.get_hash/2
Gets the SHA-256 hash for given data and nonce.
Parameters:
data(binary): The input datanonce(integer): The nonce value
Returns:
{:ok, hash}- Hex-encoded hash string{:error, reason}- Hashing failed
Examples
Blockchain Mining Simulation
defmodule BlockchainMiner do
def mine_block(transactions, previous_hash, difficulty) do
block_data = "#{previous_hash}#{Enum.join(transactions, ",")}"
case Powex.compute_parallel(block_data, difficulty, 8) do
{:ok, nonce} ->
{:ok, hash} = Powex.get_hash(block_data, nonce)
%{
transactions: transactions,
previous_hash: previous_hash,
nonce: nonce,
hash: hash,
difficulty: difficulty
}
{:error, reason} ->
{:error, "Mining failed: #{reason}"}
end
end
def validate_block(block) do
block_data = "#{block.previous_hash}#{Enum.join(block.transactions, ",")}"
Powex.valid?(block_data, block.nonce, block.difficulty)
end
end
# Mine a new block
block = BlockchainMiner.mine_block(
["tx1", "tx2", "tx3"],
"previous_block_hash",
4
)
# Validate the block
BlockchainMiner.validate_block(block)
# => truePerformance Benchmarking
defmodule Powex.Benchmark do
def benchmark_difficulty(data, max_difficulty) do
Enum.map(1..max_difficulty, fn difficulty ->
{time, {:ok, nonce}} = :timer.tc(Powex, :compute, [data, difficulty])
%{
difficulty: difficulty,
time_microseconds: time,
nonce: nonce
}
end)
end
end
# Benchmark different difficulties
results = Powex.Benchmark.benchmark_difficulty("benchmark_data", 6)Performance Considerations
- Difficulty Scaling: Computation time increases exponentially with difficulty
- Parallel Processing: Use
compute_parallel/3for difficulties > 4 - Thread Count: Optimal thread count usually equals CPU core count
- Memory Usage: Minimal memory footprint, CPU-bound operation
Building from Source
# Clone the repository
git clone <repository_url>
cd powex
# Install dependencies
mix deps.get
# Compile (this will build the Rust NIF)
mix compile
# Run tests
mix testBenchmarks
mix run examples/benchmark.exs
=== Powex Performance Benchmark ===
1. Sequential vs Parallel Performance:
Sequential: 96.56 ms (nonce: 24294)
Parallel: 97.79 ms (nonce: 24294)
Speedup: 0.99x
2. Difficulty Scaling Analysis:
Difficulty 1: 0.0 ms (nonce: 0)
Hash: 0b1fca060b522c417263...
Difficulty 2: 0.51 ms (nonce: 133)
Hash: 001a95cc256f9155afa5...
Difficulty 3: 60.62 ms (nonce: 15715)
Hash: 000a950b8318c1215e9c...
Difficulty 4: 170.5 ms (nonce: 43671)
Hash: 0000f91202ddfac2fc89...
Difficulty 5: 2739.71 ms (nonce: 716595)
Hash: 00000cb04780051c45f5...
3. Thread Scaling Performance:
1 threads: 53.25 ms (nonce: 13199)
2 threads: 52.53 ms (nonce: 13199)
4 threads: 60.11 ms (nonce: 13199)
8 threads: 79.46 ms (nonce: 13199)
4. Hash Rate Estimation:
Computed 2776 hashes in 10.75 ms
Hash rate: 258185.0 H/s
=== Benchmark completed ===Thank you for making it this far ๐ค