mirror of
https://github.com/vacp2p/zerokit.git
synced 2026-01-06 20:33:53 -05:00
feat(rln-wasm): seperate rln wasm parallel package (#360)
This commit is contained in:
13
.github/workflows/nightly-release.yml
vendored
13
.github/workflows/nightly-release.yml
vendored
@@ -115,17 +115,16 @@ jobs:
|
||||
run: make installdeps
|
||||
- name: Build rln-wasm package
|
||||
run: |
|
||||
if [[ ${{ matrix.feature }} == *parallel* ]]; then
|
||||
if [[ ${{ matrix.feature }} == "parallel" ]]; then
|
||||
env CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUSTFLAGS="-C target-feature=+atomics,+bulk-memory,+mutable-globals -C link-arg=--shared-memory -C link-arg=--max-memory=1073741824 -C link-arg=--import-memory -C link-arg=--export=__wasm_init_tls -C link-arg=--export=__tls_size -C link-arg=--export=__tls_align -C link-arg=--export=__tls_base" \
|
||||
rustup run nightly wasm-pack build --release --target web --scope waku \
|
||||
--features ${{ matrix.feature }} -Z build-std=panic_abort,std
|
||||
else
|
||||
wasm-pack build --release --target web --scope waku
|
||||
fi
|
||||
|
||||
if [[ ${{ matrix.feature }} == "utils" ]]; then
|
||||
--features parallel -Z build-std=panic_abort,std
|
||||
sed -i.bak 's/rln-wasm/zerokit-rln-wasm-parallel/g' pkg/package.json && rm pkg/package.json.bak
|
||||
elif [[ ${{ matrix.feature }} == "utils" ]]; then
|
||||
wasm-pack build --release --target web --scope waku --no-default-features --features utils
|
||||
sed -i.bak 's/rln-wasm/zerokit-rln-wasm-utils/g' pkg/package.json && rm pkg/package.json.bak
|
||||
else
|
||||
wasm-pack build --release --target web --scope waku
|
||||
sed -i.bak 's/rln-wasm/zerokit-rln-wasm/g' pkg/package.json && rm pkg/package.json.bak
|
||||
fi
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@ dependencies = ["pack_build", "pack_rename", "pack_add_keywords"]
|
||||
|
||||
[tasks.build_parallel]
|
||||
clear = true
|
||||
dependencies = ["pack_build_parallel", "pack_rename", "pack_add_keywords"]
|
||||
dependencies = [
|
||||
"pack_build_parallel",
|
||||
"pack_rename_parallel",
|
||||
"pack_add_keywords",
|
||||
]
|
||||
|
||||
[tasks.build_utils]
|
||||
clear = true
|
||||
@@ -14,6 +18,9 @@ dependencies = ["pack_build_utils", "pack_rename_utils", "pack_add_keywords"]
|
||||
command = "wasm-pack"
|
||||
args = ["build", "--release", "--target", "web", "--scope", "waku"]
|
||||
|
||||
[tasks.pack_rename]
|
||||
script = "sed -i.bak 's/rln-wasm/zerokit-rln-wasm/g' pkg/package.json && rm pkg/package.json.bak"
|
||||
|
||||
[tasks.pack_build_parallel]
|
||||
command = "env"
|
||||
args = [
|
||||
@@ -34,8 +41,8 @@ args = [
|
||||
"build-std=panic_abort,std",
|
||||
]
|
||||
|
||||
[tasks.pack_rename]
|
||||
script = "sed -i.bak 's/rln-wasm/zerokit-rln-wasm/g' pkg/package.json && rm pkg/package.json.bak"
|
||||
[tasks.pack_rename_parallel]
|
||||
script = "sed -i.bak 's/rln-wasm/zerokit-rln-wasm-parallel/g' pkg/package.json && rm pkg/package.json.bak"
|
||||
|
||||
[tasks.pack_build_utils]
|
||||
command = "wasm-pack"
|
||||
|
||||
@@ -14,145 +14,92 @@ RLN functionality in JavaScript/TypeScript applications.
|
||||
> [!NOTE]
|
||||
> This project requires the following tools:
|
||||
>
|
||||
> - `wasm-pack` - for compiling Rust to WebAssembly
|
||||
> - `wasm-pack` (v0.13.1) - for compiling Rust to WebAssembly
|
||||
> - `cargo-make` - for running build commands
|
||||
> - `nvm` - to install and manage Node.js
|
||||
>
|
||||
> Ensure all dependencies are installed before proceeding.
|
||||
> - `nvm` - to install and manage Node.js (v22.14.0+)
|
||||
|
||||
### Manually
|
||||
|
||||
#### Install `wasm-pack`
|
||||
|
||||
```bash
|
||||
cargo install wasm-pack --version=0.13.1
|
||||
```
|
||||
|
||||
#### Install `cargo-make`
|
||||
|
||||
```bash
|
||||
cargo install cargo-make
|
||||
```
|
||||
|
||||
#### Install `Node.js`
|
||||
|
||||
If you don't have `nvm` (Node Version Manager), install it by following
|
||||
the [installation instructions](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script).
|
||||
|
||||
After installing `nvm`, install and use Node.js `v22.14.0`:
|
||||
|
||||
```bash
|
||||
nvm install 22.14.0
|
||||
nvm use 22.14.0
|
||||
nvm alias default 22.14.0
|
||||
```
|
||||
|
||||
If you already have Node.js installed,
|
||||
check your version with `node -v` command — the version must be strictly greater than 22.
|
||||
|
||||
### Or install everything
|
||||
|
||||
You can run the following command from the root of the repository to install all required dependencies for `zerokit`
|
||||
### Quick Install
|
||||
|
||||
```bash
|
||||
make installdeps
|
||||
```
|
||||
|
||||
## Building the library
|
||||
### Manual Installation
|
||||
|
||||
First, navigate to the rln-wasm directory:
|
||||
```bash
|
||||
# Install wasm-pack
|
||||
cargo install wasm-pack --version=0.13.1
|
||||
|
||||
# Install cargo-make
|
||||
cargo install cargo-make
|
||||
|
||||
# Install Node.js via nvm
|
||||
nvm install 22.14.0
|
||||
nvm use 22.14.0
|
||||
nvm alias default 22.14.0
|
||||
```
|
||||
|
||||
## Building the Library
|
||||
|
||||
Navigate to the rln-wasm directory:
|
||||
|
||||
```bash
|
||||
cd rln-wasm
|
||||
```
|
||||
|
||||
Compile zerokit for `wasm32-unknown-unknown`:
|
||||
Build commands:
|
||||
|
||||
```bash
|
||||
cargo make build
|
||||
cargo make build # Default → @waku/zerokit-rln-wasm
|
||||
cargo make build_parallel # Parallel → @waku/zerokit-rln-wasm-parallel (requires nightly Rust)
|
||||
cargo make build_utils # Utils only → @waku/zerokit-rln-wasm-utils
|
||||
```
|
||||
|
||||
Or you can build the utility functions only without RLN proof generation and verification:
|
||||
All packages output to `pkg/` directory.
|
||||
|
||||
## Running Tests and Benchmarks
|
||||
|
||||
```bash
|
||||
cargo make build_utils
|
||||
```
|
||||
|
||||
## Running tests and benchmarks
|
||||
|
||||
```bash
|
||||
cargo make test
|
||||
```
|
||||
|
||||
If you want to run the tests in browser headless mode, you can use the following command:
|
||||
|
||||
```bash
|
||||
cargo make test_browser
|
||||
```
|
||||
|
||||
If you want to test only the utility functions after running `cargo make build_utils`, you can use the following command:
|
||||
|
||||
```bash
|
||||
cargo make test_utils
|
||||
cargo make test # Standard tests
|
||||
cargo make test_browser # Browser headless mode
|
||||
cargo make test_utils # Utils-only tests
|
||||
cargo make test_parallel # Parallel tests
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Working examples demonstrating proof generation, proof verification and slashing:
|
||||
See [Node example](./examples/index.js) and [README](./examples/Readme.md) for proof generation, verification, and slashing.
|
||||
|
||||
- [Node example](./examples/index.js) and [README](./examples/Readme.md)
|
||||
## Parallel Computation
|
||||
|
||||
## Parallel computation
|
||||
|
||||
The library supports parallel computation using the `wasm-bindgen-rayon` crate,
|
||||
enabling multi-threaded execution in the browser.
|
||||
Enables multi-threaded browser execution using `wasm-bindgen-rayon`.
|
||||
|
||||
> [!NOTE]
|
||||
> Parallel support is not enabled by default due to WebAssembly and browser limitations. \
|
||||
> Compiling this feature requires `nightly` Rust.
|
||||
>
|
||||
> - Parallel support is not enabled by default due to WebAssembly and browser limitations.
|
||||
> - Requires `nightly` Rust: `rustup install nightly`
|
||||
> - Browser-only (not compatible with Node.js)
|
||||
> - Requires HTTP headers for `SharedArrayBuffer`:
|
||||
> - `Cross-Origin-Opener-Policy: same-origin`
|
||||
> - `Cross-Origin-Embedder-Policy: require-corp`
|
||||
|
||||
### Build Setup
|
||||
### Usage
|
||||
|
||||
#### Install `nightly` Rust
|
||||
Direct usage (modern browsers with WebAssembly threads support):
|
||||
|
||||
```bash
|
||||
rustup install nightly
|
||||
```js
|
||||
import * as wasmPkg from '@waku/zerokit-rln-wasm-parallel';
|
||||
|
||||
await wasmPkg.default();
|
||||
await wasmPkg.initThreadPool(navigator.hardwareConcurrency);
|
||||
wasmPkg.nowCallAnyExportedFuncs();
|
||||
```
|
||||
|
||||
### Build Commands
|
||||
### Feature Detection for Older Browsers
|
||||
|
||||
To enable parallel computation for WebAssembly threads, you can use the following command:
|
||||
If you're targeting [older browser versions that didn't support WebAssembly threads yet](https://webassembly.org/roadmap/), you'll want to use both builds - the parallel version for modern browsers and the default version as a fallback. Use feature detection to choose the appropriate build on the JavaScript side.
|
||||
|
||||
```bash
|
||||
cargo make build_parallel
|
||||
```
|
||||
|
||||
### Running parallel tests and benchmarks
|
||||
|
||||
If you want to run the parallel tests in browser headless mode, you can use the following command:
|
||||
|
||||
```bash
|
||||
cargo make test_parallel
|
||||
```
|
||||
|
||||
### WebAssembly Threads Support
|
||||
|
||||
Most modern browsers support WebAssembly threads,
|
||||
but they require the following headers to enable `SharedArrayBuffer`, which is necessary for multithreading:
|
||||
|
||||
- Cross-Origin-Opener-Policy: same-origin
|
||||
- Cross-Origin-Embedder-Policy: require-corp
|
||||
|
||||
Without these, the application will fall back to single-threaded mode.
|
||||
|
||||
## Feature detection
|
||||
|
||||
If you're targeting [older browser versions that didn't support WebAssembly threads yet](https://webassembly.org/roadmap/),
|
||||
you'll likely want to create two builds - one with threads support and one without -
|
||||
and use feature detection to choose the right one on the JavaScript side.
|
||||
|
||||
You can use [wasm-feature-detect](https://github.com/GoogleChromeLabs/wasm-feature-detect) library for this purpose.
|
||||
For example, your code might look like this:
|
||||
You can use the [wasm-feature-detect](https://github.com/GoogleChromeLabs/wasm-feature-detect) library for this purpose:
|
||||
|
||||
```js
|
||||
import { threads } from 'wasm-feature-detect';
|
||||
@@ -160,11 +107,11 @@ import { threads } from 'wasm-feature-detect';
|
||||
let wasmPkg;
|
||||
|
||||
if (await threads()) {
|
||||
wasmPkg = await import('./pkg-with-threads/index.js');
|
||||
wasmPkg = await import('@waku/zerokit-rln-wasm-parallel');
|
||||
await wasmPkg.default();
|
||||
await wasmPkg.initThreadPool(navigator.hardwareConcurrency);
|
||||
} else {
|
||||
wasmPkg = await import('./pkg-without-threads/index.js');
|
||||
wasmPkg = await import('@waku/zerokit-rln-wasm');
|
||||
await wasmPkg.default();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Compile and Run
|
||||
# RLN WASM Node Examples
|
||||
|
||||
## Build the rln-wasm package at the root of rln-wasm
|
||||
This example demonstrates how to use the RLN WASM package in a Node.js environment.
|
||||
|
||||
## Build the @waku/zerokit-rln-wasm package at the root of rln-wasm module
|
||||
|
||||
```bash
|
||||
cargo make build
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Compile and Run
|
||||
# RLN FFI C example
|
||||
|
||||
This example demonstrates how to use the RLN C FFI in both stateless and non-stateless modes.
|
||||
|
||||
## Non-stateless mode
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
# RLN Nim FFI example
|
||||
# RLN FFI Nim example
|
||||
|
||||
This example shows how to use the RLN C FFI from Nim in stateless mode. It demonstrates:
|
||||
This example demonstrates how to use the RLN C FFI from Nim in both stateless and non-stateless modes. It covers:
|
||||
|
||||
- Creating an RLN handle using the stateless constructor
|
||||
- Building a witness for a mock Merkle path (no exported tree APIs)
|
||||
- Generating a proof and verifying it
|
||||
- Creating an RLN handle (stateless or with Merkle tree backend)
|
||||
- Generating identity keys and commitments
|
||||
- Building a witness (mock Merkle path in stateless mode, real Merkle proof in non-stateless mode)
|
||||
- Generating and verifying a proof
|
||||
- Serializing/deserializing FFI objects (CFr, Vec\<CFr>, RLNWitnessInput, RLNProof, RLNProofValues)
|
||||
- Simulating a double-signaling attack and recovering the identity secret
|
||||
|
||||
## Build the RLN library
|
||||
|
||||
@@ -29,10 +32,10 @@ This produces the shared library in `target/release`:
|
||||
From this directory:
|
||||
|
||||
```bash
|
||||
# Stateless (uses local mock path, no tree exports)
|
||||
# Stateless mode (no tree APIs, uses mock Merkle path)
|
||||
nim c -d:release -d:ffiStateless main.nim
|
||||
|
||||
# Non-stateless (uses exported tree APIs to insert leaf and fetch proof)
|
||||
# Non-stateless mode (uses exported tree APIs to insert leaf and fetch proof)
|
||||
nim c -d:release main.nim
|
||||
```
|
||||
|
||||
@@ -66,41 +69,56 @@ $env:PATH = "$PWD\..\..\target\release;$env:PATH"
|
||||
./main.exe
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
You should see detailed output showing each step, for example:
|
||||
|
||||
```powershell
|
||||
RLN created
|
||||
Witness built
|
||||
Proof generated
|
||||
Verify: OK
|
||||
```text
|
||||
Creating RLN instance
|
||||
RLN instance created successfully
|
||||
|
||||
Generating identity keys
|
||||
Identity generated
|
||||
- identity_secret = ...
|
||||
- id_commitment = ...
|
||||
|
||||
Creating message limit
|
||||
- user_message_limit = ...
|
||||
|
||||
Computing rate commitment
|
||||
- rate_commitment = ...
|
||||
|
||||
CFr serialization: CFr <-> bytes
|
||||
- serialized rate_commitment = ...
|
||||
- deserialized rate_commitment = ...
|
||||
|
||||
Vec<CFr> serialization: Vec<CFr> <-> bytes
|
||||
- serialized keys = ...
|
||||
- deserialized keys = ...
|
||||
|
||||
... (Merkle path, hashing, witness, proof, verification, and slashing steps) ...
|
||||
|
||||
Proof verified successfully
|
||||
Slashing successful: Identity is recovered!
|
||||
```
|
||||
|
||||
## What the example does (stateless mode)
|
||||
## What the example does
|
||||
|
||||
1) Creates an RLN handle via the stateless constructor.
|
||||
### Stateless mode
|
||||
|
||||
2) Generates identity keys and sets a `user_message_limit` and `message_id`.
|
||||
1. Creates an RLN handle via the stateless constructor.
|
||||
2. Generates identity keys, sets a `user_message_limit` and `message_id`.
|
||||
3. Hashes a signal, epoch, and RLN identifier to field elements.
|
||||
4. Computes `rateCommitment = Poseidon(id_commitment, user_message_limit)`.
|
||||
5. Builds a mock Merkle path for an empty depth-20 tree at index 0 (no exported tree APIs):
|
||||
- Path siblings: level 0 sibling is `0`, then each level uses precomputed default hashes `H(0,0)`, `H(H(0,0),H(0,0))`, ...
|
||||
- Path indices: all zeros (left at every level)
|
||||
- Root: folds the path upwards with `rateCommitment` at index 0
|
||||
6. Builds the witness, generates the proof, and verifies it with `ffi_verify_with_roots`, passing a one-element roots vector containing the computed root.
|
||||
7. Simulates a double-signaling attack and recovers the identity secret from two proofs.
|
||||
|
||||
3) Hashes a signal and external nullifier (`ffi_hash`).
|
||||
### Non-stateless mode
|
||||
|
||||
4) Computes `rateCommitment = Poseidon(id_commitment, user_message_limit)` using `ffi_poseidon_hash`.
|
||||
|
||||
5) Builds a mock Merkle path for an empty depth-20 tree at index 0 (no exported tree APIs):
|
||||
|
||||
- Path siblings: level 0 sibling is `0`,
|
||||
then each level uses precomputed default hashes `H(0,0)`, `H(H(0,0),H(0,0))`, ...
|
||||
- Path indices: all zeros (left at every level)
|
||||
- Root: folds the path upwards with `rateCommitment` at index 0
|
||||
|
||||
6) Builds the witness, generates the proof, and verifies it with `ffi_verify_with_roots`,
|
||||
passing a one-element roots vector containing the computed root (length must be 1).
|
||||
|
||||
## What the example does (non-stateless mode)
|
||||
|
||||
1) Creates an RLN handle with a Merkle tree backend and configuration.
|
||||
|
||||
2) Generates identity keys and computes `rateCommitment = Poseidon(id_commitment, user_message_limit)`.
|
||||
|
||||
3) Inserts the leaf with `ffi_set_next_leaf` and fetches a real Merkle path for index 0 via `ffi_get_merkle_proof`.
|
||||
|
||||
4) Builds the witness from the exported proof, generates the proof, and verifies with `ffi_verify_rln_proof` using the current tree root.
|
||||
1. Creates an RLN handle with a Merkle tree backend and configuration.
|
||||
2. Generates identity keys and computes `rateCommitment = Poseidon(id_commitment, user_message_limit)`.
|
||||
3. Inserts the leaf with `ffi_set_next_leaf` and fetches a real Merkle path for index 0 via `ffi_get_merkle_proof`.
|
||||
4. Builds the witness from the exported proof, generates the proof, and verifies with `ffi_verify_rln_proof` using the current tree root.
|
||||
5. Simulates a double-signaling attack and recovers the identity secret from two proofs.
|
||||
|
||||
Reference in New Issue
Block a user