In the world of crypto currency there’s no shortage of people who shun the use of FPGA technology for acceleration of crypto currency algorithms because they feel it’s not accessible to the general public. Reasons for this vary but fall along the lines of “the tools are too expensive” or “the hardware is not accessible” or even “they’re too difficult to program”. In the past some of this may have held some ground but with the introduction Xilinx® Vitis™ unified software platform, combined with readily available FPGA acceleration boards in the cloud, this article is going to dispel these concerns as mere myths.
This article will use Ethereum as an example and demonstrate how easy it is to take the core algorithm of a crypto currency blockchain, such as Ethash in the case of Ethereum, and start accelerating it with an FPGA. This will be done using standard C++ and OpenCL without the need for costly tools and using hardware easily accessible to everybody. Enjoy!
Ethash is the name of the hashing algorithm that is at the core of all Ethereum transactions. This algorithm is used as a proof-of-work (PoW) that a substantial amount of distributed effort when towards the creation of a transaction (i.e. a new block in the chain). The PoW is a key part of how fraudulent transactions are prevented. When so called ‘miners’ participate in the block chain they are using compute power to try to solve the PoW and those who solve it are rewarded with some crypto currency (hence the ‘mining’ aspect of it). The more compute power a miner has the more likely they are to solve PoWs. For this article we will measure compute power in a very straight forward manner: hashes per second.
So let’s start by checking the compute power of a relatively high-end CPU. This will also introduce the source code of the Ethash algorithm which will later be used in the Vitis tool.
The Ethash algorithm is both formally published in a paper and maintained in a public Git repository. The paper, named the ‘Yellowpaper’ by the creators of Ethereum, is available here:
It describes not only the PoW, but the entire Ethereum system. The PoW, or Ethash, is described in gory mathematical detail in Appendix J of this yellow paper. In theory, you could write your own code based on this yellow paper but a quick look at the Appendix J will probably turn most people off of this option. So we will opt to use some code that has already been written for us and available on Github here:
This particular source should be quite reliable as it’s one of many repositories maintained by Ethereum.org. In fact, the yellow paper itself is also maintained at this Git location.
Steps to fetch and build the code are shown below. To ensure consistent results a specific version of the code is checked out: v23.1. This was the most recent tagged version at the time.
$ git clone https://github.com/ethereum/ethash.git $ git checkout v23.1 $ cd ethash
The code will build a library for various supported languages including C++ and Python but first some dependencies must be met.
$ sudo apt install libboost-dev libboost-all-dev
The above libs are leveraged to build and test the code. The code can also, optionally, leverage libcrypto++ (a.k.a. libcryptopp), but I found the unit tests failed when I added a more recent version so I’ve omitted installation of this.
With dependencies met, running Make should result in something similar to below.
$ make ./test/test.sh ################# Testing JS ################## ################# Testing C ################## make: Entering directory '/home/ethash/test/c/build' make: Entering directory '/home/ethash/test/c/build' make: Entering directory '/home/ethash/test/c/build' make: Entering directory '/home/ethash/test/c/build' Scanning dependencies of target ethash make: Leaving directory '/home/ethash/test/c/build' make: Entering directory '/home/ethash/test/c/build' [ 16%] Building C object src/libethash/CMakeFiles/ethash.dir/util.c.o [ 33%] Building C object src/libethash/CMakeFiles/ethash.dir/internal.c.o [ 50%] Building C object src/libethash/CMakeFiles/ethash.dir/sha3.c.o [ 66%] Linking C static library libethash.a make: Leaving directory '/home/ethash/test/c/build' [ 66%] Built target ethash make: Entering directory '/home/ethash/test/c/build' Scanning dependencies of target Test make: Leaving directory '/home/ethash/test/c/build' make: Entering directory '/home/ethash/test/c/build' [ 83%] Building CXX object test/c/CMakeFiles/Test.dir/test.cpp.o [100%] Linking CXX executable Test make: Leaving directory '/home/ethash/test/c/build' [100%] Built target Test make: Leaving directory '/home/ethash/test/c/build' make: Leaving directory '/home/ethash/test/c/build' make: Leaving directory '/home/ethash/test/c/build' Running 7 test cases... *** No errors detected ################# Testing Python ################## /home/ethash/test/python/test.sh: line 14: virtualenv: command not found Makefile:3: recipe for target 'test' failed make: *** [test] Error 127
Since we’re only after the C build at this point the error for the Python build can be safely ignored. Running the top-level Make will kick-off CMake which in-turn generates Make files for the available languages. Next we will build for C as follow:
$ cd test/c/build $ make help $ make ethash
TIP: If you run into errors running Make you can modify the ethash/test/c/test.sh file to replace
cmake ../../.. > /dev/null
This will provide more output about CMake generation and dependency checks.
This builds and places the Ethash static library at ethash/test/c/build/src/libethash/libethash.a for which we can build some provided benchmarking code. As should have been seen after running Make with the ‘help’ option there are several targets available in addition to just the library. For a test that mimics the way a miner would use Ethash we’ll want to build and run the Benchmark_FULL program. However, the code seems to be missing a statement when built without the previously mentioned libcrypto++ so we’ll quickly fix this first. Simply open ethash/src/benchmark/benchmark.cpp and make the addition highlighted below.
#else #include "libethash/sha3.h" #include <string> #endif // WITH_CRYPTOPP
Now we can build as normal:
$ make Benchmark_FULL [ 66%] Built target ethash Scanning dependencies of target Benchmark_FULL [ 83%] Building CXX object src/benchmark/CMakeFiles/Benchmark_FULL.dir/benchmark.cpp.o [100%] Linking CXX executable Benchmark_FULL [100%] Built target Benchmark_FULL
Now the benchmarking application can be run. An example of some results is given below. Note that since this was built on a computer without GPU hardware (or with respect to the software without OpenCL) these results are an example of pure CPU performance.
$ ./src/benchmark/Benchmark_FULL ethash_mkcache: 782ms, sha3: 6a286c5fc0f36814732c86c3e71c036dd96d58def86b9244bb1480571e67d2a8 ethash_light test: 4ms, a7ea1de3a8007134900cd2c86f7e55af68a1d3e4537438a0a966b6cbafa23c90 ethash_compute_full_data: 671116ms ethash_full test: 25ns, a7ea1de3a8007134900cd2c86f7e55af68a1d3e4537438a0a966b6cbafa23c90 hashrate: 59425, bw: 464 MB/s
Actually running the benchmark program can take quite sometime as seen by the “671116ms” (~11mins) taken to create the full dataset in the case above, but the results indicate a rate of ~59.4k hashes per second with an individual hash generated in 25ns.
The hexadecimal output given by the benchmark program represent 32-byte hash values with the last two representing the actual output of the PoW; they were simply calculated in two different ways.
Now that we have an idea of where to get the PoW code, how to build it, and how to test it let’s move on to bringing the code into acceleration tools.
Shaun Purvis is a Processor Specialist Field Application Engineer (FAE) covering Eastern Canada. He works across a variety of industries, including Wired/Wireless Communications, Audio/Video Broadcast, and Industrial Vision, supporting embedded applications as well as artificial intelligence (AI) solutions. Prior to Xilinx Shaun worked at a consulting company as an ARM processor and Xilinx SoC specialist where he did a lot of globetrotting and training as the embedded industry embraced these technologies. Shaun grew up on the West Coast of BC, graduated from McGill University, and started his professional career in California. He now lives with his family in Montreal where he enjoys scaling up mountains in summer and sliding down them in winter.