Just released: SHA-256, SHA-512, SHA-1, and RIPEMD-160 using WebAssembly
TL;DR: up to 20x better performance than JavaScript, and up to 4x faster than Node.js native bindings for small inputs. (But you should look at the benchmarks yourself.)
You can now import WebAssembly implementations of the cryptographic hash functions used in cryptocurrencies like Bitcoin and Bitcoin Cash from the bitcoin-ts
library on NPM:
npm install bitcoin-ts
The API is purely-functional, fully-typed and documented with TypeScript, and accepts and returns native ES2015 typed arrays.
Below is an example of SHA-256 and RIPEMD-160 being used to validate part of a Bitcoin/Bitcoin Cash transaction. We instantiate the WebAssembly versions of SHA-256 and RIPEMD-160, then we hash pubkey
, first with SHA-256, then with RIPEMD-160 to get the correct pubkeyHash
.
Thoroughly tested against existing implementations
Each hash function implementation is compiled from the excellent, well-reviewed, Rust Crypto library. In addition, the WebAssembly versions are tested against hash.js
, bcrypto
(the library used in bcoin
), and the built-in Node.js hash function implementations (which use OpenSSL).
The generated WebAssembly binary is also auditable and deterministic — you can rebuild it easily yourself and verify that the NPM-distributed version is correct. Simply clone the repo from GitHub and follow the directions there.
Up to 20x better performance than JavaScript, faster than Node.js native bindings for small inputs
You can see the benchmarks on GitHub. Here are some notable observations.
These benchmarks are all over the place
Performance varies drastically between applications. While there are clear themes in the above benchmarks, in many cases, there’s no obvious winner.
If hashing is a performance bottleneck in your application, you’ll need to benchmark the options specifically for your workload.
JavaScript can be really fast
JavaScript engines (like v8, which is used in Node.js) are incredibly good at optimizing code. While the WebAssembly implementations in bitcoin-ts
are generally much faster than the pure JavaScript implementation, the SHA-1 JavaScript implementation slightly outperforms WebAssembly on inputs of 32 bytes or less.
Though WebAssembly implementations also beat JavaScript on small input sizes for the other hash functions, it’s truly impressive that v8 is able to optimize the SHA-1 method so well.
Bcoin is the fastest on Node.js
If you need the very best performance for Node.js, Bcoin is probably your answer. It outperforms the Node.js built-in methods in nearly every case.
Particularly for the SHA functions, Bcoin and the Node.js built-in implementations perform more than 2x better than WebAssembly. This appears to be a result of their access to hardware SHA256 acceleration (RIPEMD-160 for large inputs is 50% faster in WebAssembly than native).
WebAssembly is extremely fast everywhere
The WebAssembly implementations are up to 4x faster than the built-in Node.js implementations (especially for smaller inputs), and easily outperform the pure JavaScript implementation (between 2x and 20x, depending on the use case).
WebAssembly is also remarkably consistent — while other implementations rise and fall in the rankings based on workload, the WebAssembly implementations perform fairly consistently in all cases.
Wrapping up
With this addition, bitcoin-ts
now includes all the cryptographic primitives used in most Bitcoin and Bitcoin Cash nodes and wallets. If you have any questions or feedback, or if you’re using bitcoin-ts
in your own projects, please let me know on Twitter.