All projects

BSc Thesis · 2024

Fairness in Hashcash through Memory-Hard Functions

Hashcash rewards whoever owns the most specialised silicon. Swapping SHA-256 for Argon2 changes that economics — this thesis measured by how much, with CUDA benchmarks rather than argument.

Role
Sole author — implementation, benchmarking, analysis
Context
BSc Computer Science thesis, VU Amsterdam
Timeline
July 2024
Stack
  • C++
  • CUDA
  • Argon2d
  • SHA-256
  • Python
  • Benchmarking

Read the thesis (PDF)

The problem

Hashcash, proposed in 1997 to combat junk mail, asks a sender to find a nonce whose SHA-256 hash carries a required number of leading zeroes. Finding one is expensive; verifying one is trivial. That asymmetry is the whole mechanism, and it now underpins consensus in Bitcoin among other systems.

SHA-256 work is pure compute over a tiny working set — precisely the workload specialised hardware eats. ASICs designed to do nothing but SHA-256 solve the puzzle several thousand times faster than a desktop. The result is a barrier to entry for anyone without that hardware, and, where a proof-of-work network is meant to be decentralised, a real path to majority control.

Memory-hard functions attack this directly. Force the computation to occupy a large memory matrix whose blocks depend on each other, and the constraint shifts from raw compute throughput to memory capacity and latency — where a GPU's lead over a CPU is far narrower, because memory latency is broadly similar across platforms using the same technology.

So the research question: can Argon2 replace SHA-256 in Hashcash and produce a fairer, more accessible proof-of-work?

Approach

Argon2d — the Password Hashing Competition winner, in the data-dependent indexing variant specifically optimised to resist GPU cracking — was implemented as the hash underlying Hashcash, and benchmarked head to head against SHA-256.

  • Argon2 exposes three parameters that matter here: memory cost (size of the memory matrix), time cost (iterations over it), and parallelism (threads per hash instance). Each was swept rather than fixed.
  • Benchmarking ran on an NVIDIA RTX 4070 (5,888 CUDA cores, 12 GB global memory) against an Intel i7-7700K (4 cores / 8 threads), via CUDA under WSL2.
  • Metrics: hash rate (KH/s or MH/s), hash count to solution, and mean hash time — batch size serving as the measure of parallelism in play.
  • Every configuration was repeated ten times and averaged, because hash counts to a solution vary enormously run to run.
Two line charts. Left: Argon2D and SHA256 hash rate in kilohashes per second against batch size; Argon2D plateaus around 22 KH/s then collapses sharply past a batch size of roughly 1150, while SHA256 climbs slowly to around 7 KH/s. Right: SHA256 on GPU in megahashes per second, rising to a plateau near 40 MH/s.
Left: Argon2d against SHA-256 by batch size (KH/s). Right: SHA-256 alone, in MH/s — note the unit change. The apparent Argon2d lead on the left is an artefact of scale.

Findings

40 MH/sSHA-256 peak on GPU
~22 KH/sArgon2d peak on the same GPU
~2 H/swhere a tuned Argon2d instance puts GPU and CPU on par

The memory wall is real, and it is a cliff

Argon2d's hash rate rises to roughly 22 KH/s and then collapses past a batch size around 1,150, as the GPU's 12 GB global memory limit is approached and running more instances in parallel stops being possible. SHA-256 shows no such wall — it scales smoothly to about 40 MH/s, three orders of magnitude higher in absolute terms.

That collapse is the mechanism working as intended. The memory cost parameter defines an upper bound on parallelism for a given piece of hardware, and therefore a ceiling on hash rate that no amount of compute throughput can lift.

Crashes during benchmarking were treated as data rather than noise: the point at which the CUDA implementation failed to queue workloads exceeding the memory limit marks exactly where computational feasibility ends for that hardware.

Tuning to a target, not to a maximum

The practical output is a procedure, not a single recommended configuration. Since Argon2's parameters set both a parallelism ceiling and a per-instance runtime, they can be tuned so that a desired hash rate — and therefore a desired time-to-solution — is reached on a target architecture, and so that faster hardware gains little by exceeding it.

Worked through concretely: at Hashcash difficulty 5, Argon2d took a mean of 4,698 attempts to find a solution. For a ten-minute target that implies roughly 8 hashes per second. With the memory cost set accordingly, eight parallel Argon2d instances would need about 1.9 GiB each — consuming all 16 GB of the test CPU's RAM. The 12 GB GPU could only run six, making it less efficient than the CPU for this configuration.

Tested directly at a target of 2–2.5 H/s, the GPU achieved no significantly higher hash rate than the CPU. That is the central result: with Argon2d, unlike SHA-256, the performance gap between a consumer GPU and a commodity CPU can be closed to nothing.

Attempts-to-solution stays comparable

At difficulty 5, SHA-256 averaged 847 attempts against Argon2d's 5,085 — but SHA-256's spread ran from 65 to 1,574 attempts, so the ranges overlap heavily. Mean hash count does not change significantly with Argon2's memory cost parameter, which means difficulty tuning and memory-hardness tuning are largely independent knobs.

Limitations

  • No ASIC access. A consumer GPU approximates specialised hardware; it is not a substitute for testing against one.
  • WSL2 and Python. GPU access went through WSL2, likely costing bandwidth, and the CPU-side Hashcash implementation was interpreted Python — both depress absolute numbers, though they affect the comparison less than the headline figures.
  • Argon2d is side-channel exposed. Data-dependent indexing is vulnerable to cache-timing attacks. Whether that yields a practical time advantage in a proof-of-work setting was outside scope, and is the most important open question left.
  • Weaker systems were not modelled. The analysis focused on preventing stronger hardware from gaining an edge, not on what Argon2's memory demands cost a low-spec machine.

Conclusion

Argon2 can be implemented within Hashcash and tuned to perform consistently across hardware configurations. Minor differences between systems remain, but they do not exhibit the vast discrepancies SHA-256 produces — which makes Argon2 a viable, fairer alternative to the current SHA-256 construction.

Want the detail?

Happy to share the thesis or walk through the benchmark methodology.

hendrikjoel21@gmail.com