Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rln-cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions rln-cli/src/examples/multi_message_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use std::{
use clap::{Parser, Subcommand};
use rln::prelude::{
default_graph_multi, default_zkey_multi, hash_to_field_le, keygen, poseidon_hash,
ArkGroth16Backend, Fr, IdSecret, PmTree, PmTreeSledConfig, PoseidonHash, RLNBuilder,
RLNProofValues, RLNWitnessInput, RecoverSecret, SledDB, Stateful, RLN,
ArkGroth16Backend, Fr, PmTree, PmTreeSledConfig, PoseidonHash, RLNBuilder, RLNProofValues,
RLNWitnessInput, RecoverSecret, SecretFr, SledDB, Stateful, RLN,
};
use zerokit_utils::merkle_tree::{Hasher, ZerokitMerkleProof, ZerokitMerkleTree};

Expand Down Expand Up @@ -46,7 +46,7 @@ enum Commands {

#[derive(Debug, Clone)]
struct Identity {
identity_secret: IdSecret,
identity_secret: SecretFr,
id_commitment: Fr,
}

Expand Down
6 changes: 3 additions & 3 deletions rln-cli/src/examples/partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use std::{
use clap::{Parser, Subcommand};
use rln::prelude::{
default_graph_single, default_zkey_single, hash_to_field_le, keygen, poseidon_hash,
ArkGroth16Backend, Fr, IdSecret, PartialProof, PoseidonHash, RLNBuilder,
RLNPartialWitnessInput, RLNProofValues, RLNWitnessInput, RecoverSecret, Stateful, RLN,
ArkGroth16Backend, Fr, PartialProof, PoseidonHash, RLNBuilder, RLNPartialWitnessInput,
RLNProofValues, RLNWitnessInput, RecoverSecret, SecretFr, Stateful, RLN,
};
use zerokit_utils::merkle_tree::{FullMerkleTree, Hasher, ZerokitMerkleProof, ZerokitMerkleTree};

Expand Down Expand Up @@ -48,7 +48,7 @@ enum Commands {

#[derive(Debug, Clone)]
struct Identity {
identity_secret: IdSecret,
identity_secret: SecretFr,
id_commitment: Fr,
}

Expand Down
6 changes: 3 additions & 3 deletions rln-cli/src/examples/relay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use std::{
use clap::{Parser, Subcommand};
use rln::prelude::{
graph_from_raw, hash_to_field_le, keygen, poseidon_hash, zkey_from_raw, ArkGroth16Backend, Fr,
IdSecret, PmTree, PmTreeMode, PmTreeSledConfig, PoseidonHash, RLNBuilder, RLNProofValues,
RLNWitnessInput, RecoverSecret, SledDB, Stateful, RLN,
PmTree, PmTreeMode, PmTreeSledConfig, PoseidonHash, RLNBuilder, RLNProofValues,
RLNWitnessInput, RecoverSecret, SecretFr, SledDB, Stateful, RLN,
};
use zerokit_utils::merkle_tree::{Hasher, ZerokitMerkleProof, ZerokitMerkleTree};

Expand Down Expand Up @@ -44,7 +44,7 @@ enum Commands {

#[derive(Debug, Clone)]
struct Identity {
identity_secret: IdSecret,
identity_secret: SecretFr,
id_commitment: Fr,
}

Expand Down
6 changes: 3 additions & 3 deletions rln-cli/src/examples/stateless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use std::{
use clap::{Parser, Subcommand};
use rln::prelude::{
default_graph_single, default_zkey_single, hash_to_field_le, keygen, poseidon_hash,
ArkGroth16Backend, Fr, IdSecret, PoseidonHash, RLNBuilder, RLNProofValues, RLNWitnessInput,
RecoverSecret, Stateless, DEFAULT_TREE_DEPTH, RLN,
ArkGroth16Backend, Fr, PoseidonHash, RLNBuilder, RLNProofValues, RLNWitnessInput,
RecoverSecret, SecretFr, Stateless, DEFAULT_TREE_DEPTH, RLN,
};
use zerokit_utils::merkle_tree::{
Hasher, OptimalMerkleTree, ZerokitMerkleProof, ZerokitMerkleTree,
Expand Down Expand Up @@ -43,7 +43,7 @@ enum Commands {

#[derive(Debug, Clone)]
struct Identity {
identity_secret: IdSecret,
identity_secret: SecretFr,
id_commitment: Fr,
}

Expand Down
2 changes: 2 additions & 0 deletions rln-wasm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rln-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ wasm-bindgen-rayon = { version = "1.3.0", features = [
ark-relations = { version = "0.5.1", features = ["std"] }
ark-groth16 = { version = "0.5.0", default-features = false }
rand = "0.8.6"
zeroize = "1.8.2"

# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
Expand Down
22 changes: 11 additions & 11 deletions rln-wasm/examples/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export async function initRLN(enableMultiMessageId = false) {

export function createMember(rlnWasm) {
console.log("\nGenerating identity keys");
const identity = rlnWasm.Identity.generate();
const identitySecret = identity.getSecretHash();
const identity = rlnWasm.WasmIdentityKeys.generate();
const identitySecret = identity.getSecret();
const idCommitment = identity.getCommitment();
console.log(" - identity generated successfully");
console.log(" - identity secret = " + identitySecret.debug());
Expand All @@ -59,7 +59,7 @@ export function createMember(rlnWasm) {
console.log(" - user message limit = " + userMessageLimit.debug());

console.log("\nComputing rate commitment");
const rateCommitment = rlnWasm.Hasher.poseidonHashPair(
const rateCommitment = rlnWasm.WasmHasher.poseidonHashPair(
idCommitment,
userMessageLimit,
);
Expand All @@ -79,9 +79,9 @@ export function computeMerkleProof(rlnWasm, rateCommitment) {
const defaultLeaf = rlnWasm.WasmFr.zero();

const defaultHashes = [];
defaultHashes[0] = rlnWasm.Hasher.poseidonHashPair(defaultLeaf, defaultLeaf);
defaultHashes[0] = rlnWasm.WasmHasher.poseidonHashPair(defaultLeaf, defaultLeaf);
for (let i = 1; i < TREE_DEPTH - 1; i++) {
defaultHashes[i] = rlnWasm.Hasher.poseidonHashPair(
defaultHashes[i] = rlnWasm.WasmHasher.poseidonHashPair(
defaultHashes[i - 1],
defaultHashes[i - 1],
);
Expand All @@ -96,12 +96,12 @@ export function computeMerkleProof(rlnWasm, rateCommitment) {

console.log("\nComputing Merkle root for stateless mode");
console.log(" - computing root for index 0 with rate commitment");
let computedRoot = rlnWasm.Hasher.poseidonHashPair(
let computedRoot = rlnWasm.WasmHasher.poseidonHashPair(
rateCommitment,
defaultLeaf,
);
for (let i = 1; i < TREE_DEPTH; i++) {
computedRoot = rlnWasm.Hasher.poseidonHashPair(
computedRoot = rlnWasm.WasmHasher.poseidonHashPair(
computedRoot,
defaultHashes[i - 1],
);
Expand All @@ -115,7 +115,7 @@ export function computeMerkleProof(rlnWasm, rateCommitment) {
}

export function hashSignal(rlnWasm, signal) {
return rlnWasm.Hasher.hashToFieldLE(signal);
return rlnWasm.WasmHasher.hashToFieldLE(signal);
}

export function computeExternalNullifier(
Expand All @@ -124,19 +124,19 @@ export function computeExternalNullifier(
rlnIdStr = "test-rln-identifier",
) {
console.log("\nHashing epoch");
const epoch = rlnWasm.Hasher.hashToFieldLE(
const epoch = rlnWasm.WasmHasher.hashToFieldLE(
new TextEncoder().encode(epochStr),
);
console.log(" - epoch = " + epoch.debug());

console.log("\nHashing RLN identifier");
const rlnIdentifier = rlnWasm.Hasher.hashToFieldLE(
const rlnIdentifier = rlnWasm.WasmHasher.hashToFieldLE(
new TextEncoder().encode(rlnIdStr),
);
console.log(" - RLN identifier = " + rlnIdentifier.debug());

console.log("\nComputing Poseidon hash for external nullifier");
const externalNullifier = rlnWasm.Hasher.poseidonHashPair(
const externalNullifier = rlnWasm.WasmHasher.poseidonHashPair(
epoch,
rlnIdentifier,
);
Expand Down
4 changes: 3 additions & 1 deletion rln-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ pub use wasm_rln::{
WasmRLN, WasmRLNPartialProof, WasmRLNPartialWitnessInput, WasmRLNProof, WasmRLNProofValues,
WasmRLNWitnessInput,
};
pub use wasm_utils::{ExtendedIdentity, Hasher, Identity, VecWasmFr, WasmFr};
pub use wasm_utils::{
VecWasmFr, WasmExtendedIdentityKeys, WasmFr, WasmHasher, WasmIdentityKeys, WasmSecretFr,
};

#[cfg(feature = "panic_hook")]
#[wasm_bindgen(js_name = initPanicHook)]
Expand Down
29 changes: 13 additions & 16 deletions rln-wasm/src/wasm_rln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use js_sys::Uint8Array;
use rln::prelude::*;
use wasm_bindgen::prelude::*;

use crate::wasm_utils::{VecWasmFr, WasmFr};
use crate::wasm_utils::{VecWasmFr, WasmFr, WasmSecretFr};

// WasmRLN

Expand Down Expand Up @@ -100,20 +100,19 @@ pub struct WasmRLNWitnessInput(RLNWitnessInput);
impl WasmRLNWitnessInput {
#[wasm_bindgen(js_name = newSingle)]
pub fn new_single(
identity_secret: &WasmFr,
identity_secret: &WasmSecretFr,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing this only now but is there a reason we use reference here everywhere? Because, for example, it requires to clone the secret here so almost no reason no?

@vinhtc27 vinhtc27 Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it has a good reason to do so.

WASM take & for all non-primitive types because with wasm-bindgen, a by-value param moves ownership, the JS object gets its internal pointer nulled after the call. JS has no move semantics, so callers don't expect this:

const keys = WasmIdentityKeys.generate();
const secret = keys.getSecret();
const w1 = WasmRLNWitnessInput.newSingle(secret, ...); // if by-value: secret is consumed here
const w2 = WasmRLNWitnessInput.newSingle(secret, ...); // throws "null pointer passed to rust"

With & the object stays alive and we clone once inside instead. Otherwise we need to provide clone() fn.

The same idea apply for FFI too.

user_message_limit: &WasmFr,
message_id: &WasmFr,
path_elements: &VecWasmFr,
identity_path_index: &Uint8Array,
x: &WasmFr,
external_nullifier: &WasmFr,
) -> Result<WasmRLNWitnessInput, String> {
let mut identity_secret_fr = identity_secret.inner();
let path_elements: Vec<Fr> = path_elements.inner();
let identity_path_index: Vec<u8> = identity_path_index.to_vec();

let witness = RLNWitnessInput::new_single()
.identity_secret(IdSecret::from(&mut identity_secret_fr))
.identity_secret(identity_secret.inner().clone())
.user_message_limit(user_message_limit.inner())
.path_elements(path_elements)
.identity_path_index(identity_path_index)
Expand All @@ -129,7 +128,7 @@ impl WasmRLNWitnessInput {
#[allow(clippy::too_many_arguments)]
#[wasm_bindgen(js_name = newMulti)]
pub fn new_multi(
identity_secret: &WasmFr,
identity_secret: &WasmSecretFr,
user_message_limit: &WasmFr,
message_ids: VecWasmFr,
path_elements: &VecWasmFr,
Expand All @@ -138,15 +137,14 @@ impl WasmRLNWitnessInput {
external_nullifier: &WasmFr,
selector_used: Uint8Array,
) -> Result<WasmRLNWitnessInput, String> {
let mut identity_secret_fr = identity_secret.inner();
let path_elements: Vec<Fr> = path_elements.inner();
let identity_path_index: Vec<u8> = identity_path_index.to_vec();

let message_ids: Vec<Fr> = message_ids.inner();
let selector_used: Vec<bool> = selector_used.to_vec().iter().map(|&b| b != 0).collect();

let witness = RLNWitnessInput::new_multi()
.identity_secret(IdSecret::from(&mut identity_secret_fr))
.identity_secret(identity_secret.inner().clone())
.user_message_limit(user_message_limit.inner())
.path_elements(path_elements)
.identity_path_index(identity_path_index)
Expand All @@ -161,8 +159,8 @@ impl WasmRLNWitnessInput {
}

#[wasm_bindgen(js_name = getIdentitySecret)]
pub fn get_identity_secret(&self) -> WasmFr {
WasmFr::from(**self.0.identity_secret())
pub fn get_identity_secret(&self) -> WasmSecretFr {
WasmSecretFr::from(self.0.identity_secret().clone())
}

#[wasm_bindgen(js_name = getUserMessageLimit)]
Expand Down Expand Up @@ -256,17 +254,16 @@ pub struct WasmRLNPartialWitnessInput(RLNPartialWitnessInput);
impl WasmRLNPartialWitnessInput {
#[wasm_bindgen(js_name = new)]
pub fn new(
identity_secret: &WasmFr,
identity_secret: &WasmSecretFr,
user_message_limit: &WasmFr,
path_elements: &VecWasmFr,
identity_path_index: &Uint8Array,
) -> Result<WasmRLNPartialWitnessInput, String> {
let mut identity_secret_fr = identity_secret.inner();
let path_elements: Vec<Fr> = path_elements.inner();
let identity_path_index: Vec<u8> = identity_path_index.to_vec();

let witness = RLNPartialWitnessInput::new()
.identity_secret(IdSecret::from(&mut identity_secret_fr))
.identity_secret(identity_secret.inner().clone())
.user_message_limit(user_message_limit.inner())
.path_elements(path_elements)
.identity_path_index(identity_path_index)
Expand Down Expand Up @@ -472,22 +469,22 @@ impl WasmRLNProofValues {
share1_y: &WasmFr,
share2_x: &WasmFr,
share2_y: &WasmFr,
) -> Result<WasmFr, String> {
) -> Result<WasmSecretFr, String> {
let share1 = (share1_x.inner(), share1_y.inner());
let share2 = (share2_x.inner(), share2_y.inner());
let secret = compute_id_secret(share1, share2).map_err(|err| err.to_string())?;
Ok(WasmFr::from(*secret))
Ok(WasmSecretFr::from(secret))
}

#[wasm_bindgen(js_name = recoverIdSecret)]
pub fn recover_id_secret(
proof_values_1: &WasmRLNProofValues,
proof_values_2: &WasmRLNProofValues,
) -> Result<WasmFr, String> {
) -> Result<WasmSecretFr, String> {
let recovered_identity_secret = proof_values_1
.0
.recover_secret(&proof_values_2.0)
.map_err(|err| err.to_string())?;
Ok(WasmFr::from(*recovered_identity_secret))
Ok(WasmSecretFr::from(recovered_identity_secret))
}
}
Loading
Loading