@waku/rln 0.0.2-ce9a6ae.0 → 0.0.2-e3aa837.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/bundle/index.js +1 -1
  2. package/bundle/packages/interfaces/dist/protocols.js +40 -45
  3. package/bundle/packages/rln/dist/contract/abi.js +648 -0
  4. package/bundle/packages/rln/dist/contract/constants.js +8 -13
  5. package/bundle/packages/rln/dist/contract/rln_contract.js +14 -3
  6. package/bundle/packages/rln/dist/identity.js +0 -46
  7. package/bundle/packages/rln/dist/rln.js +37 -15
  8. package/bundle/packages/rln/dist/zerokit.js +22 -16
  9. package/dist/.tsbuildinfo +1 -1
  10. package/dist/contract/{abi/rlnv2.d.ts → abi.d.ts} +22 -18
  11. package/dist/contract/abi.js +647 -0
  12. package/dist/contract/abi.js.map +1 -0
  13. package/dist/contract/constants.d.ts +22 -23
  14. package/dist/contract/constants.js +7 -12
  15. package/dist/contract/constants.js.map +1 -1
  16. package/dist/contract/rln_contract.d.ts +8 -0
  17. package/dist/contract/rln_contract.js +14 -3
  18. package/dist/contract/rln_contract.js.map +1 -1
  19. package/dist/identity.d.ts +0 -7
  20. package/dist/identity.js +0 -46
  21. package/dist/identity.js.map +1 -1
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +2 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/rln.js +37 -14
  26. package/dist/rln.js.map +1 -1
  27. package/dist/zerokit.d.ts +5 -1
  28. package/dist/zerokit.js +22 -16
  29. package/dist/zerokit.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/contract/abi.ts +646 -0
  32. package/src/contract/constants.ts +8 -14
  33. package/src/contract/rln_contract.ts +16 -3
  34. package/src/identity.ts +0 -70
  35. package/src/index.ts +2 -2
  36. package/src/rln.ts +52 -14
  37. package/src/zerokit.ts +45 -16
  38. package/bundle/node_modules/@iden3/js-crypto/dist/browser/esm/index.js +0 -7
  39. package/bundle/node_modules/@stablelib/binary/lib/binary.js +0 -22
  40. package/bundle/node_modules/@stablelib/chacha/lib/chacha.js +0 -245
  41. package/bundle/node_modules/@stablelib/wipe/lib/wipe.js +0 -26
  42. package/bundle/packages/rln/dist/contract/abi/rlnv2.js +0 -394
  43. package/dist/__tests__/identity.test.d.ts +0 -1
  44. package/dist/__tests__/identity.test.js +0 -40
  45. package/dist/__tests__/identity.test.js.map +0 -1
  46. package/dist/contract/abi/rlnv2.js +0 -393
  47. package/dist/contract/abi/rlnv2.js.map +0 -1
  48. package/src/__tests__/identity.test.ts +0 -50
  49. package/src/contract/abi/rlnv2.ts +0 -392
@@ -1,9 +1,10 @@
1
- import { RLN_V2_ABI } from "./abi/rlnv2.js";
1
+ import { RLN_ABI } from "./abi.js";
2
2
 
3
3
  export const SEPOLIA_CONTRACT = {
4
- chainId: 11155111,
5
- address: "0xCB33Aa5B38d79E3D9Fa8B10afF38AA201399a7e3",
6
- abi: RLN_V2_ABI
4
+ chainId: 59141,
5
+ // Implementation contract: 0xde2260ca49300357d5af4153cda0d18f7b3ea9b3
6
+ address: "0xb9cd878c90e49f797b4431fbf4fb333108cb90e6",
7
+ abi: RLN_ABI
7
8
  };
8
9
 
9
10
  /**
@@ -17,19 +18,12 @@ export const RATE_LIMIT_TIERS = {
17
18
  HIGH: 600 // Suggested maximum rate - 600 messages per epoch
18
19
  } as const;
19
20
 
20
- // Default to maximum rate limit if not specified
21
- export const DEFAULT_RATE_LIMIT = RATE_LIMIT_TIERS.HIGH;
22
-
23
- /**
24
- * Epoch length in seconds (10 minutes)
25
- * This is a constant defined in the smart contract
26
- */
27
- export const EPOCH_LENGTH = 600;
28
-
29
21
  // Global rate limit parameters
30
22
  export const RATE_LIMIT_PARAMS = {
31
23
  MIN_RATE: RATE_LIMIT_TIERS.LOW,
32
24
  MAX_RATE: RATE_LIMIT_TIERS.HIGH,
33
25
  MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
34
- EPOCH_LENGTH: EPOCH_LENGTH // Epoch length in seconds (10 minutes)
26
+ EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
35
27
  } as const;
28
+
29
+ export const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
@@ -8,7 +8,7 @@ import type { RLNInstance } from "../rln.js";
8
8
  import { MerkleRootTracker } from "../root_tracker.js";
9
9
  import { zeroPadLE } from "../utils/bytes.js";
10
10
 
11
- import { RLN_V2_ABI } from "./abi/rlnv2.js";
11
+ import { RLN_ABI } from "./abi.js";
12
12
  import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./constants.js";
13
13
 
14
14
  const log = new Logger("waku:rln:contract");
@@ -108,8 +108,7 @@ export class RLNContract {
108
108
  const initialRoot = rlnInstance.zerokit.getMerkleRoot();
109
109
 
110
110
  // Use the injected contract if provided; otherwise, instantiate a new one.
111
- this.contract =
112
- contract || new ethers.Contract(address, RLN_V2_ABI, signer);
111
+ this.contract = contract || new ethers.Contract(address, RLN_ABI, signer);
113
112
  this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
114
113
 
115
114
  // Initialize event filters for MembershipRegistered and MembershipRemoved
@@ -124,6 +123,20 @@ export class RLNContract {
124
123
  return this.rateLimit;
125
124
  }
126
125
 
126
+ /**
127
+ * Gets the contract address
128
+ */
129
+ public get address(): string {
130
+ return this.contract.address;
131
+ }
132
+
133
+ /**
134
+ * Gets the contract provider
135
+ */
136
+ public get provider(): ethers.providers.Provider {
137
+ return this.contract.provider;
138
+ }
139
+
127
140
  /**
128
141
  * Gets the minimum allowed rate limit from the contract
129
142
  * @returns Promise<number> The minimum rate limit in messages per epoch
package/src/identity.ts CHANGED
@@ -1,15 +1,5 @@
1
- import { arrayify } from "@ethersproject/bytes";
2
- import { keccak256 } from "@ethersproject/keccak256";
3
- import { Poseidon } from "@iden3/js-crypto";
4
- import { streamXOR } from "@stablelib/chacha";
5
-
6
1
  import { buildBigIntFromUint8Array } from "./utils/index.js";
7
2
 
8
- // BN254 curve field size (Snark friendly curve)
9
- const BN254_FIELD_SIZE = BigInt(
10
- "21888242871839275222246405745257275088548364400416034343698204186575808495617"
11
- );
12
-
13
3
  export class IdentityCredential {
14
4
  public constructor(
15
5
  public readonly IDTrapdoor: Uint8Array,
@@ -38,64 +28,4 @@ export class IdentityCredential {
38
28
  idCommitmentBigInt
39
29
  );
40
30
  }
41
-
42
- /**
43
- * Normalizes a bigint to be within the BN254 field size
44
- * @param value The bigint value to normalize
45
- * @returns A bigint value that is within the field size
46
- */
47
- private static normalizeToFieldSize(value: bigint): bigint {
48
- // Apply modulo operation to ensure the value is within the field
49
- return value % BN254_FIELD_SIZE;
50
- }
51
-
52
- public static generateSeeded(signature: Uint8Array): IdentityCredential {
53
- try {
54
- // Generate deterministic seed from signature
55
- const seed = arrayify(keccak256(signature));
56
-
57
- // Use ChaCha for deterministic randomness (as in Rust code)
58
- const nonce = new Uint8Array(12);
59
- const idSecretHash = new Uint8Array(32);
60
- streamXOR(seed, nonce, idSecretHash, idSecretHash);
61
-
62
- // Convert to bigint for Poseidon
63
- const secretBigInt = BigInt(
64
- "0x" + Buffer.from(idSecretHash).toString("hex")
65
- );
66
-
67
- // Normalize the value to be within the field size
68
- const normalizedSecretBigInt = this.normalizeToFieldSize(secretBigInt);
69
-
70
- // Generate commitment using Poseidon with normalized value
71
- const idCommitmentBigInt = Poseidon.hash([normalizedSecretBigInt]);
72
-
73
- // Convert commitment back to Uint8Array
74
- const idCommitment = arrayify(
75
- "0x" + idCommitmentBigInt.toString(16).padStart(64, "0")
76
- );
77
-
78
- // Generate deterministic trapdoor and nullifier from the secret hash
79
- const idTrapdoor = new Uint8Array(32);
80
- const idNullifier = new Uint8Array(32);
81
- streamXOR(idSecretHash, nonce, idTrapdoor, idTrapdoor);
82
- streamXOR(idTrapdoor, nonce, idNullifier, idNullifier);
83
-
84
- return new IdentityCredential(
85
- idTrapdoor,
86
- idNullifier,
87
- idSecretHash,
88
- idCommitment,
89
- idCommitmentBigInt
90
- );
91
- } catch (error) {
92
- // Additional fallback for any other errors
93
- if (error instanceof Error) {
94
- throw new Error(
95
- `Failed to generate identity credential: ${error.message}`
96
- );
97
- }
98
- throw error;
99
- }
100
- }
101
31
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RLNDecoder, RLNEncoder } from "./codec.js";
2
- import { RLN_V2_ABI } from "./contract/abi/rlnv2.js";
2
+ import { RLN_ABI } from "./contract/abi.js";
3
3
  import { RLNContract, SEPOLIA_CONTRACT } from "./contract/index.js";
4
4
  import { createRLN } from "./create.js";
5
5
  import { IdentityCredential } from "./identity.js";
@@ -21,5 +21,5 @@ export {
21
21
  RLNContract,
22
22
  SEPOLIA_CONTRACT,
23
23
  extractMetaMaskSigner,
24
- RLN_V2_ABI
24
+ RLN_ABI
25
25
  };
package/src/rln.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  type RLNDecoder,
16
16
  type RLNEncoder
17
17
  } from "./codec.js";
18
+ import { DEFAULT_RATE_LIMIT } from "./contract/constants.js";
18
19
  import { RLNContract, SEPOLIA_CONTRACT } from "./contract/index.js";
19
20
  import { IdentityCredential } from "./identity.js";
20
21
  import { Keystore } from "./keystore/index.js";
@@ -32,15 +33,46 @@ import { Zerokit } from "./zerokit.js";
32
33
  const log = new Logger("waku:rln");
33
34
 
34
35
  async function loadWitnessCalculator(): Promise<WitnessCalculator> {
35
- const url = new URL("./resources/rln.wasm", import.meta.url);
36
- const response = await fetch(url);
37
- return await wc.builder(new Uint8Array(await response.arrayBuffer()), false);
36
+ try {
37
+ const url = new URL("./resources/rln.wasm", import.meta.url);
38
+ const response = await fetch(url);
39
+
40
+ if (!response.ok) {
41
+ throw new Error(
42
+ `Failed to fetch witness calculator: ${response.status} ${response.statusText}`
43
+ );
44
+ }
45
+
46
+ return await wc.builder(
47
+ new Uint8Array(await response.arrayBuffer()),
48
+ false
49
+ );
50
+ } catch (error) {
51
+ log.error("Error loading witness calculator:", error);
52
+ throw new Error(
53
+ `Failed to load witness calculator: ${error instanceof Error ? error.message : String(error)}`
54
+ );
55
+ }
38
56
  }
39
57
 
40
58
  async function loadZkey(): Promise<Uint8Array> {
41
- const url = new URL("./resources/rln_final.zkey", import.meta.url);
42
- const response = await fetch(url);
43
- return new Uint8Array(await response.arrayBuffer());
59
+ try {
60
+ const url = new URL("./resources/rln_final.zkey", import.meta.url);
61
+ const response = await fetch(url);
62
+
63
+ if (!response.ok) {
64
+ throw new Error(
65
+ `Failed to fetch zkey: ${response.status} ${response.statusText}`
66
+ );
67
+ }
68
+
69
+ return new Uint8Array(await response.arrayBuffer());
70
+ } catch (error) {
71
+ log.error("Error loading zkey:", error);
72
+ throw new Error(
73
+ `Failed to load zkey: ${error instanceof Error ? error.message : String(error)}`
74
+ );
75
+ }
44
76
  }
45
77
 
46
78
  /**
@@ -61,7 +93,7 @@ export async function create(): Promise<RLNInstance> {
61
93
 
62
94
  const DEPTH = 20;
63
95
  const zkRLN = zerokitRLN.newRLN(DEPTH, zkey, vkey);
64
- const zerokit = new Zerokit(zkRLN, witnessCalculator);
96
+ const zerokit = new Zerokit(zkRLN, witnessCalculator, DEFAULT_RATE_LIMIT);
65
97
 
66
98
  return new RLNInstance(zerokit);
67
99
  } catch (error) {
@@ -142,7 +174,7 @@ export class RLNInstance {
142
174
  this._contract = await RLNContract.init(this, {
143
175
  address: address!,
144
176
  signer: signer!,
145
- rateLimit: options.rateLimit
177
+ rateLimit: options.rateLimit ?? this.zerokit.getRateLimit
146
178
  });
147
179
  this.started = true;
148
180
  } finally {
@@ -164,6 +196,13 @@ export class RLNInstance {
164
196
  chainId = SEPOLIA_CONTRACT.chainId;
165
197
  }
166
198
 
199
+ // eslint-disable-next-line no-console
200
+ console.log({
201
+ chainId,
202
+ address,
203
+ SEPOLIA_CONTRACT
204
+ });
205
+
167
206
  const signer = options.signer || (await extractMetaMaskSigner());
168
207
  const currentChainId = await signer.getChainId();
169
208
 
@@ -214,12 +253,11 @@ export class RLNInstance {
214
253
  throw Error("RLN Contract is not initialized.");
215
254
  }
216
255
 
217
- let identity: IdentityCredential | undefined =
218
- "identity" in options ? options.identity : undefined;
256
+ let identity = "identity" in options && options.identity;
219
257
 
220
258
  if ("signature" in options) {
221
- identity = IdentityCredential.generateSeeded(
222
- ethers.utils.arrayify(options.signature)
259
+ identity = this.zerokit.generateSeededIdentityCredential(
260
+ options.signature
223
261
  );
224
262
  }
225
263
 
@@ -272,7 +310,7 @@ export class RLNInstance {
272
310
  }
273
311
 
274
312
  const registryAddress = credentials.membership.address;
275
- const currentRegistryAddress = this._contract.contract.address;
313
+ const currentRegistryAddress = this._contract.address;
276
314
  if (registryAddress !== currentRegistryAddress) {
277
315
  throw Error(
278
316
  `Failed to verify chain coordinates: credentials contract address=${registryAddress} is not equal to registryContract address=${currentRegistryAddress}`
@@ -280,7 +318,7 @@ export class RLNInstance {
280
318
  }
281
319
 
282
320
  const chainId = credentials.membership.chainId;
283
- const network = await this._contract.contract.provider.getNetwork();
321
+ const network = await this._contract.provider.getNetwork();
284
322
  const currentChainId = network.chainId;
285
323
  if (chainId !== currentChainId) {
286
324
  throw Error(
package/src/zerokit.ts CHANGED
@@ -15,9 +15,22 @@ import {
15
15
  export class Zerokit {
16
16
  public constructor(
17
17
  private readonly zkRLN: number,
18
- private readonly witnessCalculator: WitnessCalculator
18
+ private readonly witnessCalculator: WitnessCalculator,
19
+ private readonly rateLimit: number = DEFAULT_RATE_LIMIT
19
20
  ) {}
20
21
 
22
+ public get getZkRLN(): number {
23
+ return this.zkRLN;
24
+ }
25
+
26
+ public get getWitnessCalculator(): WitnessCalculator {
27
+ return this.witnessCalculator;
28
+ }
29
+
30
+ public get getRateLimit(): number {
31
+ return this.rateLimit;
32
+ }
33
+
21
34
  public generateIdentityCredentials(): IdentityCredential {
22
35
  const memKeys = zerokitRLN.generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm
23
36
  return IdentityCredential.fromBytes(memKeys);
@@ -67,12 +80,17 @@ export class Zerokit {
67
80
  memIndex: number,
68
81
  epoch: Uint8Array,
69
82
  idKey: Uint8Array,
70
- rateLimit: number = DEFAULT_RATE_LIMIT
83
+ rateLimit?: number
71
84
  ): Uint8Array {
72
85
  // calculate message length
73
86
  const msgLen = writeUIntLE(new Uint8Array(8), uint8Msg.length, 0, 8);
74
87
  const memIndexBytes = writeUIntLE(new Uint8Array(8), memIndex, 0, 8);
75
- const rateLimitBytes = writeUIntLE(new Uint8Array(8), rateLimit, 0, 8);
88
+ const rateLimitBytes = writeUIntLE(
89
+ new Uint8Array(8),
90
+ rateLimit ?? this.rateLimit,
91
+ 0,
92
+ 8
93
+ );
76
94
 
77
95
  // [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> | rate_limit<8> ]
78
96
  return concatenate(
@@ -90,7 +108,7 @@ export class Zerokit {
90
108
  index: number,
91
109
  epoch: Uint8Array | Date | undefined,
92
110
  idSecretHash: Uint8Array,
93
- rateLimit: number = DEFAULT_RATE_LIMIT
111
+ rateLimit?: number
94
112
  ): Promise<IRateLimitProof> {
95
113
  if (epoch === undefined) {
96
114
  epoch = epochIntToBytes(dateToEpoch(new Date()));
@@ -98,12 +116,14 @@ export class Zerokit {
98
116
  epoch = epochIntToBytes(dateToEpoch(epoch));
99
117
  }
100
118
 
119
+ const effectiveRateLimit = rateLimit ?? this.rateLimit;
120
+
101
121
  if (epoch.length !== 32) throw new Error("invalid epoch");
102
122
  if (idSecretHash.length !== 32) throw new Error("invalid id secret hash");
103
123
  if (index < 0) throw new Error("index must be >= 0");
104
124
  if (
105
- rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
106
- rateLimit > RATE_LIMIT_PARAMS.MAX_RATE
125
+ effectiveRateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
126
+ effectiveRateLimit > RATE_LIMIT_PARAMS.MAX_RATE
107
127
  ) {
108
128
  throw new Error(
109
129
  `Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`
@@ -115,7 +135,7 @@ export class Zerokit {
115
135
  index,
116
136
  epoch,
117
137
  idSecretHash,
118
- rateLimit
138
+ effectiveRateLimit
119
139
  );
120
140
  const rlnWitness = zerokitRLN.getSerializedRLNWitness(
121
141
  this.zkRLN,
@@ -150,9 +170,12 @@ export class Zerokit {
150
170
 
151
171
  // calculate message length
152
172
  const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
153
- const rateLimitBytes = rateLimit
154
- ? writeUIntLE(new Uint8Array(8), rateLimit, 0, 8)
155
- : new Uint8Array(8); // Zero if not specified
173
+ const rateLimitBytes = writeUIntLE(
174
+ new Uint8Array(8),
175
+ rateLimit ?? this.rateLimit,
176
+ 0,
177
+ 8
178
+ );
156
179
 
157
180
  return zerokitRLN.verifyRLNProof(
158
181
  this.zkRLN,
@@ -174,9 +197,12 @@ export class Zerokit {
174
197
  }
175
198
  // calculate message length
176
199
  const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
177
- const rateLimitBytes = rateLimit
178
- ? writeUIntLE(new Uint8Array(8), rateLimit, 0, 8)
179
- : new Uint8Array(8); // Zero if not specified
200
+ const rateLimitBytes = writeUIntLE(
201
+ new Uint8Array(8),
202
+ rateLimit ?? this.rateLimit,
203
+ 0,
204
+ 8
205
+ );
180
206
 
181
207
  const rootsBytes = concatenate(...roots);
182
208
 
@@ -201,9 +227,12 @@ export class Zerokit {
201
227
 
202
228
  // calculate message length
203
229
  const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
204
- const rateLimitBytes = rateLimit
205
- ? writeUIntLE(new Uint8Array(8), rateLimit, 0, 8)
206
- : new Uint8Array(8); // Zero if not specified
230
+ const rateLimitBytes = writeUIntLE(
231
+ new Uint8Array(8),
232
+ rateLimit ?? this.rateLimit,
233
+ 0,
234
+ 8
235
+ );
207
236
 
208
237
  return zerokitRLN.verifyWithRoots(
209
238
  this.zkRLN,