How to Benchmark Random Number Generation (RNG) in React Native
How to Benchmark Random Number Generation (RNG) in React Native
An analysis of crypto-save random number generation on iOS and Android via JavaScript layer in React Native.
Motivation
This article started as an effort to find a great UUID generation library. As a result, it led me to rewrite my existing react-native-uuid library in Typescript. However, I didn’t stop there. UUID generation is based on random number generation (RNG), which is an even bigger topic of Cryptography and specifically RNG.
If you don’t get your RNG right you risk having collisions between your UUIDs and your Encryption will be more vulnerable for statistical attacks.
TL;DR
RNBenchmark repo with all the code for RNG benchmarking.
react-native-benchmark library to run your benchmarks in React Native.
I’ve added subjective security ranking based on the implementation and performance of the libraries. For example, react-native-randombytes [SJCL]
uses JavaScript only implementation and thus it is the least secure library to be used on mobile. react-native-get-random-values
library has good performance and fallback. get-random-values-polypony
was rated 0 because it works great only for random values of 36 bytes or less.
Disclaimer
This article describes the early results of benchmarking methodology, and it is not perfect. I’m sure there will be better ways to measure Javascript performance and native code performance. Any feedback is welcome, and I expect to update this article as more changes are released to the above libraries.
Outline
- Why RNGs matter
- Collisions and their implications
- What libraries are analyzed in this article
- Benchmarking tools
- Methodology
- Challenges
- Results
- Limitations
- Takeaways
- Next steps
Why RNGs matter
It is a very niche topic, and most developers use off-the-shelf libraries to solve random generation. However because React Native is a different ecosystem of components compared to the browser environment and Node.js environment, it is important to understand the difference. Standard Crypto library is not available in React Native by default, and that means it’s up to you to pick a library that generates a true random number and not a pseudo one using Math.random()
inside JavaScript.
Collisions and their implications
There are two main reasons why weak random generation can cause you problems down the line and compromise the security of your encryption algorithms.
I love visual analysis, and it shows the difference between different random number generators available.
So if you use a weak RNG or a pseudo-RNG you’ll most likely compromise your encryption algorithms and make it very cheap for an attacker to exploit this vulnerability. Ask your CISO.
What will be analyzed in this article
Here’re the top 7 libraries that are still maintained and being used by the community.
You can find the full list of libraries here. While researching this topic I published another library that uses random number generation using strictly native methods in iOS and Android here. See a step-by-step tutorial on how it was built below.
How to build a react-native plugin in 2021
_A step-by-step guide to building TypeScript wrapping around native code written using Objective-C and Kotlin._medium.com
Benchmarking tools
First, I tried a 10 years old library benchmark.js that was great for other web projects, but failed on React Native, since it depends on Browser’s environment and still supports Safari 2.x and IE 🤯
I also found a nice wrapper around benchmark.js that reduces complexity a lot, but still doesn’t run on React Native.
I ended up building a drafty port that uses asynchronous callbacks and a similar API that benchmark.js uses. I used the same statistical analysis approach as they did. And used TypeScript to simplify the debugging.
react-native-benchmark
_React Native benchmarking library inspired by benchmark.js and written in TypeScript. Warning: This library is work in…_www.npmjs.com
It is not perfect and I welcome any feedback on how we can improve and stress test it!
Methodology
react-native-benchmark runs a Suite of benchmarks, where each benchmark executes each payload function at least 5 times and at least 1 second each.
After taking a more precise look at each of the tested libraries, I found that many of them have fallbacks to less compute-heavy generation and therefore I’ve broken down several of them.
- expo-random — this library should be tested inside Expo to have better results. But I was testing it inside the “ejected” state inside the clean React Native project. There’s a synchronous method
getRandomBytes
and asynchronousgetRandomBytesAsync
. In the source code, you can find that it calls firstExpoRandom.getRandomBytes
if it’s available, otherwise, it callsExpoRandom.getRandomBase64String
. Here is its native counterpart in Objective-C. If you’re installingexpo-random
you might want to see these hacks first. - react-native-randombytes is the 4th most popular library, and it also has two different methods of implementation. One is executed only in javascript using Stanford Javascript Crypto Library (SJCL). Another one — using native execution. SJCL uses
Math.random
to reseed their pools. And it also uses the entropy of different events, which is smart but can be compromised if devices are immovable. - react-native-get-random-values is the most popular library that emulates
Crypto.getRandomValues
and falls back toExpoRandom.getRandomBytes
. Check its core logic here. - react-native-securerandom is the 3rd most downloaded library, and it implements pseudo RNG fixes that bring us back to the post by Google engineers about Android’s security.
- get-random-values-polypony inherits most of the code from @consento/sync-randombytes. It creatively solved RNG, by seeding random pool using native UUID call, which provides a really nice performance on iOS and Android, compared to other native implementations when you need to generate a short (=36 bytes) sequence. However, if you want to generate something more than 36 characters (length of default UUID) you will probably want to get better entropy and run it a couple of times.
- react-native-simple-crypto library is a bigger effort to implement some cryptographic methods using native code.
- react-native-randomness is my version of the RNG library for React Native.
Here’s the main benchmarking logic: