This repository is a simple React-Native app built with Expo which demonstrates how to import a Rust library via wasm-pack
+ wasm2js
.
Specifically, this app imports the musig2
crate and uses it to securely aggregate secp256k1 public keys together. In principle this approach could be applied to any pure rust crate.
Web | Android |
---|---|
The Rust wrapper code lives in ./keyagg
, while the Expo app's entry point is App.js
.
Try out the web version on conduition.io.
Rust is the perfect platform for writing cryptographic primitives due to its precision and safety guarantees. But Rust is definitely NOT the perfect platform for front-end application development.
There are numerous easy-to-use web-app frameworks in countless languages, including some for Rust, but there are very few which support mature production-ready mobile app development.
Expo is one such framework for Javascript. Expo is built on top of React Native, which is itself built on top of React. Mobile apps built with Expo are not only easy to write, but powerful. Unlike many simple mobile frameworks, Expo provides a huge library of tools for leveraging the full power of a mobile platform, all without the need to write a single line of code in any language except Javascript.
However, Expo's simplicity comes at the price of flexibility. Expo doesn't provide an easy way to import external native libraries written in more powerful statically compiled languages like Rust, C++, or Golang. These systems languages are the typical weapon-of-choice for cryptographers, and so a wealth of mature and robust cryptographic code lives outside the reach of Expo app developers. To do so, the dev would need to surrender the simplicity of Expo and descend into the living hell of native-module linking, wrapping, and build configuration.
Who has time for that? Not me, that's for sure. Thankfully, Rust has support for WebAssembly! Huzzah!
Unfortunately, React-Native doesn't. :cry: Well, theoretically it does, but there is precious little documentation available, and the only viable-looking tool documented to work with Expo seems to be broken under the current version of React-Native.
Thankfully, right when I was nearing surrender, I found this example in the Rust wasm-bindgen
examples booklet. It describes how to use a tool called wasm2js
to compile a .wasm
file into pure JavaScript, which React-Native can compile directly.
I had to do a bit of fumbling around in the dark, but eventually got it to work correctly on both Web browsers and Android! :tada:
First, follow the Prerequisites for Local App Development with Expo.
Then follow these commands to compile an Android app or Web app using Expo.
# Install Rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add the wasm32 target for rust
rustup target add wasm32-unknown-unknown
# Install wasm-pack
cargo install wasm-pack
# Install binaryen for access to the wasm2js program
sudo apt install binaryen # Or see https://github.com/WebAssembly/binaryen for manual options
# Download this repo
git clone https://github.com/conduition/expo-wasm-demo.git && cd expo-wasm-demo
# Install NodeJS via NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install
# Alternatively, install node v20 or higher manually via some other method
# e.g. sudo apt install nodejs
# Install project dependencies
npm install
Now you're ready to rock-and-roll.
# Create an android build
make android
# Build the web-app
make web