@waku/rln 0.1.6-7fba26d.0 → 0.1.6-86bbf5b.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 (56) hide show
  1. package/bundle/_virtual/utils.js +2 -2
  2. package/bundle/_virtual/utils2.js +2 -2
  3. package/bundle/index.js +1 -1
  4. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/_sha2.js +1 -1
  5. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/hmac.js +1 -1
  6. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/pbkdf2.js +1 -1
  7. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/scrypt.js +1 -1
  8. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/sha256.js +1 -1
  9. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/sha512.js +1 -1
  10. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/utils.js +1 -1
  11. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
  12. package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
  13. package/bundle/packages/core/dist/lib/message/version_0.js +1 -4
  14. package/bundle/packages/rln/dist/contract/constants.js +7 -1
  15. package/bundle/packages/rln/dist/contract/rln_base_contract.js +10 -21
  16. package/bundle/packages/rln/dist/credentials_manager.js +14 -16
  17. package/bundle/packages/rln/dist/identity.js +40 -7
  18. package/bundle/packages/rln/dist/keystore/keystore.js +15 -11
  19. package/bundle/packages/rln/dist/message.js +11 -0
  20. package/bundle/packages/rln/dist/utils/bytes.js +37 -16
  21. package/dist/.tsbuildinfo +1 -1
  22. package/dist/contract/constants.d.ts +6 -0
  23. package/dist/contract/constants.js +6 -0
  24. package/dist/contract/constants.js.map +1 -1
  25. package/dist/contract/rln_base_contract.d.ts +0 -10
  26. package/dist/contract/rln_base_contract.js +10 -21
  27. package/dist/contract/rln_base_contract.js.map +1 -1
  28. package/dist/credentials_manager.js +14 -16
  29. package/dist/credentials_manager.js.map +1 -1
  30. package/dist/identity.d.ts +11 -2
  31. package/dist/identity.js +26 -6
  32. package/dist/identity.js.map +1 -1
  33. package/dist/keystore/keystore.js +15 -11
  34. package/dist/keystore/keystore.js.map +1 -1
  35. package/dist/message.d.ts +5 -4
  36. package/dist/message.js +2 -0
  37. package/dist/message.js.map +1 -1
  38. package/dist/utils/bytes.d.ts +12 -5
  39. package/dist/utils/bytes.js +36 -15
  40. package/dist/utils/bytes.js.map +1 -1
  41. package/dist/utils/index.d.ts +1 -1
  42. package/dist/utils/index.js +1 -1
  43. package/dist/utils/index.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/contract/constants.ts +9 -0
  46. package/src/contract/rln_base_contract.ts +12 -30
  47. package/src/credentials_manager.ts +21 -24
  48. package/src/identity.ts +41 -6
  49. package/src/keystore/keystore.ts +28 -24
  50. package/src/message.ts +7 -4
  51. package/src/utils/bytes.ts +46 -25
  52. package/src/utils/index.ts +1 -1
  53. package/dist/contract/test-utils.d.ts +0 -39
  54. package/dist/contract/test-utils.js +0 -118
  55. package/dist/contract/test-utils.js.map +0 -1
  56. package/src/contract/test-utils.ts +0 -179
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@waku/rln","version":"0.1.6-7fba26d.0","description":"RLN (Rate Limiting Nullifier) implementation for Waku","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"type":"module","homepage":"https://github.com/waku-org/js-waku/tree/master/packages/rln#readme","repository":{"type":"git","url":"https://github.com/waku-org/js-waku.git"},"bugs":{"url":"https://github.com/waku-org/js-waku/issues"},"license":"MIT OR Apache-2.0","keywords":["waku","rln","rate-limiting","privacy","web3"],"scripts":{"build":"run-s build:**","build:copy":"mkdir -p dist/resources && cp -r src/resources/* dist/resources/","build:esm":"tsc","build:bundle":"rollup --config rollup.config.js","fix":"run-s fix:*","fix:lint":"eslint src *.js --fix","check":"run-s check:*","check:tsc":"tsc -p tsconfig.dev.json","check:lint":"eslint \"src/!(resources)/**/*.{ts,js}\" *.js","check:spelling":"cspell \"{README.md,src/**/*.ts}\"","test":"NODE_ENV=test run-s test:*","test:browser":"karma start karma.conf.cjs","watch:build":"tsc -p tsconfig.json -w","watch:test":"mocha --watch","prepublish":"npm run build","reset-hard":"git clean -dfx -e .idea && git reset --hard && npm i && npm run build"},"engines":{"node":">=20"},"devDependencies":{"@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-json":"^6.0.0","@rollup/plugin-node-resolve":"^15.2.3","@types/chai":"^5.0.1","@types/chai-spies":"^1.0.6","@types/deep-equal-in-any-order":"^1.0.4","@types/lodash":"^4.17.15","@types/sinon":"^17.0.3","@waku/build-utils":"^1.0.0","@waku/message-encryption":"0.0.34-7fba26d.0","deep-equal-in-any-order":"^2.0.6","fast-check":"^3.23.2","rollup-plugin-copy":"^3.5.0"},"files":["dist","bundle","src/**/*.ts","!**/*.spec.*","!**/*.json","CHANGELOG.md","LICENSE","README.md"],"dependencies":{"@chainsafe/bls-keystore":"3.0.0","@waku/core":"0.0.36-7fba26d.0","@waku/utils":"0.0.24-7fba26d.0","@noble/hashes":"^1.2.0","@waku/zerokit-rln-wasm":"^0.0.13","ethereum-cryptography":"^3.1.0","ethers":"^5.7.2","lodash":"^4.17.21","uuid":"^11.0.5","chai":"^5.1.2","chai-as-promised":"^8.0.1","chai-spies":"^1.1.0","chai-subset":"^1.6.0","sinon":"^19.0.2"}}
1
+ {"name":"@waku/rln","version":"0.1.6-86bbf5b.0","description":"RLN (Rate Limiting Nullifier) implementation for Waku","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"type":"module","homepage":"https://github.com/waku-org/js-waku/tree/master/packages/rln#readme","repository":{"type":"git","url":"https://github.com/waku-org/js-waku.git"},"bugs":{"url":"https://github.com/waku-org/js-waku/issues"},"license":"MIT OR Apache-2.0","keywords":["waku","rln","rate-limiting","privacy","web3"],"scripts":{"build":"run-s build:**","build:copy":"mkdir -p dist/resources && cp -r src/resources/* dist/resources/","build:esm":"tsc","build:bundle":"rollup --config rollup.config.js","fix":"run-s fix:*","fix:lint":"eslint src *.js --fix","check":"run-s check:*","check:tsc":"tsc -p tsconfig.dev.json","check:lint":"eslint \"src/!(resources)/**/*.{ts,js}\" *.js","check:spelling":"cspell \"{README.md,src/**/*.ts}\"","test":"NODE_ENV=test run-s test:*","test:browser":"karma start karma.conf.cjs","watch:build":"tsc -p tsconfig.json -w","watch:test":"mocha --watch","prepublish":"npm run build","reset-hard":"git clean -dfx -e .idea && git reset --hard && npm i && npm run build"},"engines":{"node":">=20"},"devDependencies":{"@rollup/plugin-commonjs":"^25.0.7","@rollup/plugin-json":"^6.0.0","@rollup/plugin-node-resolve":"^15.2.3","@types/chai":"^5.0.1","@types/chai-spies":"^1.0.6","@waku/interfaces":"0.0.31-86bbf5b.0","@types/deep-equal-in-any-order":"^1.0.4","@types/lodash":"^4.17.15","@types/sinon":"^17.0.3","@waku/build-utils":"^1.0.0","@waku/message-encryption":"0.0.34-86bbf5b.0","deep-equal-in-any-order":"^2.0.6","fast-check":"^3.23.2","rollup-plugin-copy":"^3.5.0"},"files":["dist","bundle","src/**/*.ts","!**/*.spec.*","!**/*.json","CHANGELOG.md","LICENSE","README.md"],"dependencies":{"@chainsafe/bls-keystore":"3.0.0","@waku/core":"0.0.36-86bbf5b.0","@waku/utils":"0.0.24-86bbf5b.0","@noble/hashes":"^1.2.0","@waku/zerokit-rln-wasm":"^0.0.13","ethereum-cryptography":"^3.1.0","ethers":"^5.7.2","lodash":"^4.17.21","uuid":"^11.0.5","chai":"^5.1.2","chai-as-promised":"^8.0.1","chai-spies":"^1.1.0","chai-subset":"^1.6.0","sinon":"^19.0.2"}}
@@ -25,4 +25,13 @@ export const RATE_LIMIT_PARAMS = {
25
25
  EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
26
26
  } as const;
27
27
 
28
+ /**
29
+ * Default Q value for the RLN contract
30
+ * This is the upper bound for the ID commitment
31
+ * @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
32
+ */
33
+ export const DEFAULT_Q = BigInt(
34
+ "21888242871839275222246405745257275088548364400416034343698204186575808495617"
35
+ );
36
+
28
37
  export const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
@@ -25,12 +25,6 @@ export class RLNBaseContract {
25
25
  private minRateLimit?: number;
26
26
  private maxRateLimit?: number;
27
27
 
28
- /**
29
- * Default Q value for the RLN contract.
30
- * @see https://github.com/waku-org/waku-rlnv2-contract/blob/b7e9a9b1bc69256a2a3076c1f099b50ce84e7eff/src/WakuRlnV2.sol#L25
31
- */
32
- private Q: undefined | bigint;
33
-
34
28
  protected _members: Map<number, Member> = new Map();
35
29
  private _membersFilter: ethers.EventFilter;
36
30
  private _membershipErasedFilter: ethers.EventFilter;
@@ -85,7 +79,8 @@ export class RLNBaseContract {
85
79
  const instance = new RLNBaseContract(options);
86
80
  const [min, max] = await Promise.all([
87
81
  instance.contract.minMembershipRateLimit(),
88
- instance.contract.maxMembershipRateLimit()
82
+ instance.contract.maxMembershipRateLimit(),
83
+ instance.contract.Q()
89
84
  ]);
90
85
  instance.minRateLimit = ethers.BigNumber.from(min).toNumber();
91
86
  instance.maxRateLimit = ethers.BigNumber.from(max).toNumber();
@@ -94,17 +89,6 @@ export class RLNBaseContract {
94
89
  return instance;
95
90
  }
96
91
 
97
- /**
98
- * Fetches and caches the Q value from the contract.
99
- * @returns Promise<bigint> The Q value from the contract
100
- */
101
- public async getQ(): Promise<bigint> {
102
- if (this.Q !== undefined) return this.Q;
103
- const q = await this.contract.Q();
104
- this.Q = BigInt(q.toString());
105
- return this.Q;
106
- }
107
-
108
92
  /**
109
93
  * Gets the current rate limit for this contract instance
110
94
  */
@@ -507,7 +491,6 @@ export class RLNBaseContract {
507
491
  log.error(`Error in withdraw: ${(error as Error).message}`);
508
492
  }
509
493
  }
510
-
511
494
  public async registerWithIdentity(
512
495
  identity: IdentityCredential
513
496
  ): Promise<DecryptedCredentials | undefined> {
@@ -516,10 +499,12 @@ export class RLNBaseContract {
516
499
  `Registering identity with rate limit: ${this.rateLimit} messages/epoch`
517
500
  );
518
501
 
519
- // Check if the ID commitment is already registered
520
- const existingIndex = await this.getMemberIndex(
521
- identity.IDCommitmentBigInt
502
+ const idCommitmentBigInt = IdentityCredential.getIdCommitmentBigInt(
503
+ identity.IDCommitment
522
504
  );
505
+
506
+ // Check if the ID commitment is already registered
507
+ const existingIndex = await this.getMemberIndex(idCommitmentBigInt);
523
508
  if (existingIndex) {
524
509
  throw new Error(
525
510
  `ID commitment is already registered with index ${existingIndex}`
@@ -535,19 +520,16 @@ export class RLNBaseContract {
535
520
  }
536
521
 
537
522
  const estimatedGas = await this.contract.estimateGas.register(
538
- identity.IDCommitmentBigInt,
523
+ idCommitmentBigInt,
539
524
  this.rateLimit,
540
525
  []
541
526
  );
542
527
  const gasLimit = estimatedGas.add(10000);
543
528
 
544
529
  const txRegisterResponse: ethers.ContractTransaction =
545
- await this.contract.register(
546
- identity.IDCommitmentBigInt,
547
- this.rateLimit,
548
- [],
549
- { gasLimit }
550
- );
530
+ await this.contract.register(idCommitmentBigInt, this.rateLimit, [], {
531
+ gasLimit
532
+ });
551
533
 
552
534
  const txRegisterReceipt = await txRegisterResponse.wait();
553
535
 
@@ -643,7 +625,7 @@ export class RLNBaseContract {
643
625
  permit.v,
644
626
  permit.r,
645
627
  permit.s,
646
- identity.IDCommitmentBigInt,
628
+ IdentityCredential.getIdCommitmentBigInt(identity.IDCommitment),
647
629
  this.rateLimit,
648
630
  idCommitmentsToErase.map((id) => ethers.BigNumber.from(id))
649
631
  );
@@ -1,5 +1,5 @@
1
1
  import { hmac } from "@noble/hashes/hmac";
2
- import { sha256 } from "@noble/hashes/sha256";
2
+ import { sha256 } from "@noble/hashes/sha2";
3
3
  import { Logger } from "@waku/utils";
4
4
  import { ethers } from "ethers";
5
5
 
@@ -13,10 +13,7 @@ import type {
13
13
  } from "./keystore/index.js";
14
14
  import { KeystoreEntity, Password } from "./keystore/types.js";
15
15
  import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
16
- import {
17
- buildBigIntFromUint8Array,
18
- extractMetaMaskSigner
19
- } from "./utils/index.js";
16
+ import { extractMetaMaskSigner, switchEndianness } from "./utils/index.js";
20
17
  import { Zerokit } from "./zerokit.js";
21
18
 
22
19
  const log = new Logger("waku:credentials");
@@ -261,31 +258,31 @@ export class RLNCredentialsManager {
261
258
 
262
259
  // Generate deterministic values using HMAC-SHA256
263
260
  // We use different context strings for each component to ensure they're different
264
- const idTrapdoor = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
265
- const idNullifier = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
261
+ const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
262
+ const idNullifierBE = hmac(
263
+ sha256,
264
+ seedBytes,
265
+ encoder.encode("IDNullifier")
266
+ );
266
267
 
267
- const combinedBytes = new Uint8Array([...idTrapdoor, ...idNullifier]);
268
- const idSecretHash = sha256(combinedBytes);
268
+ const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
269
+ const idSecretHashBE = sha256(combinedBytes);
269
270
 
270
- const idCommitment = sha256(idSecretHash);
271
+ const idCommitmentBE = sha256(idSecretHashBE);
271
272
 
272
- let idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment);
273
- if (!this.contract) {
274
- throw Error("RLN contract is not initialized");
275
- }
276
-
277
- const Q = await this.contract.getQ();
278
- if (idCommitmentBigInt >= Q) {
279
- idCommitmentBigInt = idCommitmentBigInt % Q;
280
- }
273
+ // All hashing functions return big-endian bytes
274
+ // We need to switch to little-endian for the identity credential
275
+ const idTrapdoorLE = switchEndianness(idTrapdoorBE);
276
+ const idNullifierLE = switchEndianness(idNullifierBE);
277
+ const idSecretHashLE = switchEndianness(idSecretHashBE);
278
+ const idCommitmentLE = switchEndianness(idCommitmentBE);
281
279
 
282
280
  log.info("Successfully generated identity credential");
283
281
  return new IdentityCredential(
284
- idTrapdoor,
285
- idNullifier,
286
- idSecretHash,
287
- idCommitment,
288
- idCommitmentBigInt
282
+ idTrapdoorLE,
283
+ idNullifierLE,
284
+ idSecretHashLE,
285
+ idCommitmentLE
289
286
  );
290
287
  }
291
288
  }
package/src/identity.ts CHANGED
@@ -1,12 +1,22 @@
1
- import { buildBigIntFromUint8Array } from "./utils/index.js";
1
+ import { Logger } from "@waku/utils";
2
+
3
+ import { DEFAULT_Q } from "./contract/constants.js";
4
+ import {
5
+ buildBigIntFromUint8ArrayLE,
6
+ switchEndiannessBigInt
7
+ } from "./utils/bytes.js";
8
+
9
+ const log = new Logger("waku:rln:identity");
2
10
 
3
11
  export class IdentityCredential {
12
+ /**
13
+ * All variables are in little-endian format
14
+ */
4
15
  public constructor(
5
16
  public readonly IDTrapdoor: Uint8Array,
6
17
  public readonly IDNullifier: Uint8Array,
7
18
  public readonly IDSecretHash: Uint8Array,
8
- public readonly IDCommitment: Uint8Array,
9
- public readonly IDCommitmentBigInt: bigint
19
+ public readonly IDCommitment: Uint8Array
10
20
  ) {}
11
21
 
12
22
  public static fromBytes(memKeys: Uint8Array): IdentityCredential {
@@ -18,14 +28,39 @@ export class IdentityCredential {
18
28
  const idNullifier = memKeys.subarray(32, 64);
19
29
  const idSecretHash = memKeys.subarray(64, 96);
20
30
  const idCommitment = memKeys.subarray(96, 128);
21
- const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment, 32);
22
31
 
23
32
  return new IdentityCredential(
24
33
  idTrapdoor,
25
34
  idNullifier,
26
35
  idSecretHash,
27
- idCommitment,
28
- idCommitmentBigInt
36
+ idCommitment
29
37
  );
30
38
  }
39
+
40
+ /**
41
+ * Converts an ID commitment from bytes to a BigInt, normalizing it against a limit if needed
42
+ * @param bytes The ID commitment bytes to convert
43
+ * @param limit Optional limit to normalize against (Q value)
44
+ * @returns The ID commitment as a BigInt
45
+ */
46
+ public static getIdCommitmentBigInt(
47
+ idCommitment: Uint8Array,
48
+ returnType: "big-endian" | "little-endian" = "big-endian",
49
+ limit: bigint = DEFAULT_Q
50
+ ): bigint {
51
+ let idCommitmentBigIntLE = buildBigIntFromUint8ArrayLE(idCommitment);
52
+
53
+ if (limit && idCommitmentBigIntLE >= limit) {
54
+ log.warn(
55
+ `ID commitment is greater than Q, reducing it by Q: ${idCommitmentBigIntLE} % ${limit}`
56
+ );
57
+ idCommitmentBigIntLE = idCommitmentBigIntLE % limit;
58
+ }
59
+
60
+ if (returnType === "big-endian") {
61
+ return switchEndiannessBigInt(idCommitmentBigIntLE);
62
+ }
63
+
64
+ return idCommitmentBigIntLE;
65
+ }
31
66
  }
@@ -14,8 +14,6 @@ import {
14
14
  import _ from "lodash";
15
15
  import { v4 as uuidV4 } from "uuid";
16
16
 
17
- import { buildBigIntFromUint8Array } from "../utils/bytes.js";
18
-
19
17
  import { decryptEipKeystore, keccak256Checksum } from "./cipher.js";
20
18
  import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
21
19
  import type {
@@ -250,26 +248,25 @@ export class Keystore {
250
248
  const str = bytesToUtf8(bytes);
251
249
  const obj = JSON.parse(str);
252
250
 
253
- // TODO: add runtime validation of nwaku credentials
251
+ const idCommitmentLE = Keystore.fromArraylikeToBytes(
252
+ _.get(obj, "identityCredential.idCommitment", [])
253
+ );
254
+ const idTrapdoorLE = Keystore.fromArraylikeToBytes(
255
+ _.get(obj, "identityCredential.idTrapdoor", [])
256
+ );
257
+ const idNullifierLE = Keystore.fromArraylikeToBytes(
258
+ _.get(obj, "identityCredential.idNullifier", [])
259
+ );
260
+ const idSecretHashLE = Keystore.fromArraylikeToBytes(
261
+ _.get(obj, "identityCredential.idSecretHash", [])
262
+ );
263
+
254
264
  return {
255
265
  identity: {
256
- IDCommitment: Keystore.fromArraylikeToBytes(
257
- _.get(obj, "identityCredential.idCommitment", [])
258
- ),
259
- IDTrapdoor: Keystore.fromArraylikeToBytes(
260
- _.get(obj, "identityCredential.idTrapdoor", [])
261
- ),
262
- IDNullifier: Keystore.fromArraylikeToBytes(
263
- _.get(obj, "identityCredential.idNullifier", [])
264
- ),
265
- IDCommitmentBigInt: buildBigIntFromUint8Array(
266
- Keystore.fromArraylikeToBytes(
267
- _.get(obj, "identityCredential.idCommitment", [])
268
- )
269
- ),
270
- IDSecretHash: Keystore.fromArraylikeToBytes(
271
- _.get(obj, "identityCredential.idSecretHash", [])
272
- )
266
+ IDCommitment: idCommitmentLE,
267
+ IDTrapdoor: idTrapdoorLE,
268
+ IDNullifier: idNullifierLE,
269
+ IDSecretHash: idSecretHashLE
273
270
  },
274
271
  membership: {
275
272
  treeIndex: _.get(obj, "treeIndex"),
@@ -321,14 +318,21 @@ export class Keystore {
321
318
  // follows nwaku implementation
322
319
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
323
320
  private static fromIdentityToBytes(options: KeystoreEntity): Uint8Array {
321
+ function toLittleEndian(bytes: Uint8Array): Uint8Array {
322
+ return new Uint8Array(bytes).reverse();
323
+ }
324
324
  return utf8ToBytes(
325
325
  JSON.stringify({
326
326
  treeIndex: options.membership.treeIndex,
327
327
  identityCredential: {
328
- idCommitment: Array.from(options.identity.IDCommitment),
329
- idNullifier: Array.from(options.identity.IDNullifier),
330
- idSecretHash: Array.from(options.identity.IDSecretHash),
331
- idTrapdoor: Array.from(options.identity.IDTrapdoor)
328
+ idCommitment: Array.from(
329
+ toLittleEndian(options.identity.IDCommitment)
330
+ ),
331
+ idNullifier: Array.from(toLittleEndian(options.identity.IDNullifier)),
332
+ idSecretHash: Array.from(
333
+ toLittleEndian(options.identity.IDSecretHash)
334
+ ),
335
+ idTrapdoor: Array.from(toLittleEndian(options.identity.IDTrapdoor))
332
336
  },
333
337
  membershipContract: {
334
338
  chainId: options.membership.chainId,
package/src/message.ts CHANGED
@@ -1,7 +1,9 @@
1
+ import { message } from "@waku/core";
1
2
  import type {
2
3
  IDecodedMessage,
3
4
  IMessage,
4
- IRateLimitProof
5
+ IRateLimitProof,
6
+ IRlnMessage
5
7
  } from "@waku/interfaces";
6
8
  import * as utils from "@waku/utils/bytes";
7
9
 
@@ -13,12 +15,13 @@ export function toRLNSignal(contentTopic: string, msg: IMessage): Uint8Array {
13
15
  return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
14
16
  }
15
17
 
16
- export class RlnMessage<T extends IDecodedMessage> implements IDecodedMessage {
18
+ export class RlnMessage<T extends IDecodedMessage> implements IRlnMessage {
17
19
  public pubsubTopic = "";
20
+ public version = message.version_0.Version;
18
21
 
19
22
  public constructor(
20
- public rlnInstance: RLNInstance,
21
- public msg: T,
23
+ private rlnInstance: RLNInstance,
24
+ private msg: T,
22
25
  public rateLimitProof: IRateLimitProof | undefined
23
26
  ) {}
24
27
 
@@ -17,18 +17,38 @@ export function concatenate(...input: Uint8Array[]): Uint8Array {
17
17
  return result;
18
18
  }
19
19
 
20
- // Adapted from https://github.com/feross/buffer
21
- function checkInt(
22
- buf: Uint8Array,
23
- value: number,
24
- offset: number,
25
- ext: number,
26
- max: number,
27
- min: number
28
- ): void {
29
- if (value > max || value < min)
30
- throw new RangeError('"value" argument is out of bounds');
31
- if (offset + ext > buf.length) throw new RangeError("Index out of range");
20
+ export function switchEndianness(bytes: Uint8Array): Uint8Array {
21
+ return new Uint8Array(bytes.reverse());
22
+ }
23
+
24
+ /**
25
+ * Builds a BigInt from a little-endian Uint8Array
26
+ * @param bytes The little-endian bytes to convert
27
+ * @returns The resulting BigInt in little-endian format
28
+ */
29
+ export function buildBigIntFromUint8ArrayLE(bytes: Uint8Array): bigint {
30
+ let result = 0n;
31
+ for (let i = bytes.length - 1; i >= 0; i--) {
32
+ result = (result << 8n) + BigInt(bytes[i]);
33
+ }
34
+ return result;
35
+ }
36
+
37
+ /**
38
+ * Switches endianness of a bigint value
39
+ * @param value The bigint value to switch endianness for
40
+ * @returns The bigint value with reversed endianness
41
+ */
42
+ export function switchEndiannessBigInt(value: bigint): bigint {
43
+ // Convert bigint to byte array
44
+ const bytes = [];
45
+ while (value > 0n) {
46
+ bytes.push(Number(value & 0xffn));
47
+ value >>= 8n;
48
+ }
49
+
50
+ // Reverse bytes and convert back to bigint
51
+ return bytes.reverse().reduce((acc, byte) => (acc << 8n) + BigInt(byte), 0n);
32
52
  }
33
53
 
34
54
  export function writeUIntLE(
@@ -56,19 +76,6 @@ export function writeUIntLE(
56
76
  return buf;
57
77
  }
58
78
 
59
- /**
60
- * Transforms Uint8Array into BigInt
61
- * @param array: Uint8Array
62
- * @returns BigInt
63
- */
64
- export function buildBigIntFromUint8Array(
65
- array: Uint8Array,
66
- byteOffset: number = 0
67
- ): bigint {
68
- const dataView = new DataView(array.buffer);
69
- return dataView.getBigUint64(byteOffset, true);
70
- }
71
-
72
79
  /**
73
80
  * Fills with zeros to set length
74
81
  * @param array little endian Uint8Array
@@ -82,3 +89,17 @@ export function zeroPadLE(array: Uint8Array, length: number): Uint8Array {
82
89
  }
83
90
  return result;
84
91
  }
92
+
93
+ // Adapted from https://github.com/feross/buffer
94
+ function checkInt(
95
+ buf: Uint8Array,
96
+ value: number,
97
+ offset: number,
98
+ ext: number,
99
+ max: number,
100
+ min: number
101
+ ): void {
102
+ if (value > max || value < min)
103
+ throw new RangeError('"value" argument is out of bounds');
104
+ if (offset + ext > buf.length) throw new RangeError("Index out of range");
105
+ }
@@ -2,7 +2,7 @@ export { extractMetaMaskSigner } from "./metamask.js";
2
2
  export {
3
3
  concatenate,
4
4
  writeUIntLE,
5
- buildBigIntFromUint8Array,
5
+ switchEndianness,
6
6
  zeroPadLE
7
7
  } from "./bytes.js";
8
8
  export { sha256, poseidonHash } from "./hash.js";
@@ -1,39 +0,0 @@
1
- import * as ethers from "ethers";
2
- import sinon from "sinon";
3
- import type { IdentityCredential } from "../identity.js";
4
- export declare const mockRateLimits: {
5
- minRate: number;
6
- maxRate: number;
7
- maxTotalRate: number;
8
- currentTotalRate: number;
9
- };
10
- type MockProvider = {
11
- getLogs: () => never[];
12
- getBlockNumber: () => Promise<number>;
13
- getNetwork: () => Promise<{
14
- chainId: number;
15
- }>;
16
- };
17
- type MockFilters = {
18
- MembershipRegistered: () => {
19
- address: string;
20
- };
21
- MembershipErased: () => {
22
- address: string;
23
- };
24
- MembershipExpired: () => {
25
- address: string;
26
- };
27
- };
28
- export declare function createMockProvider(): MockProvider;
29
- export declare function createMockFilters(): MockFilters;
30
- type ContractOverrides = Partial<{
31
- filters: Record<string, unknown>;
32
- [key: string]: unknown;
33
- }>;
34
- export declare function createMockRegistryContract(overrides?: ContractOverrides): ethers.Contract;
35
- export declare function mockRLNRegisteredEvent(idCommitment?: string): ethers.Event;
36
- export declare function formatIdCommitment(idCommitmentBigInt: bigint): string;
37
- export declare function createRegisterStub(identity: IdentityCredential): sinon.SinonStub;
38
- export declare function verifyRegistration(decryptedCredentials: any, identity: IdentityCredential, registerStub: sinon.SinonStub, insertMemberSpy: sinon.SinonStub): void;
39
- export {};
@@ -1,118 +0,0 @@
1
- import { hexToBytes } from "@waku/utils/bytes";
2
- import { expect } from "chai";
3
- import * as ethers from "ethers";
4
- import sinon from "sinon";
5
- import { DEFAULT_RATE_LIMIT, LINEA_CONTRACT } from "./constants.js";
6
- export const mockRateLimits = {
7
- minRate: 20,
8
- maxRate: 600,
9
- maxTotalRate: 1200,
10
- currentTotalRate: 500
11
- };
12
- export function createMockProvider() {
13
- return {
14
- getLogs: () => [],
15
- getBlockNumber: () => Promise.resolve(1000),
16
- getNetwork: () => Promise.resolve({ chainId: 11155111 })
17
- };
18
- }
19
- export function createMockFilters() {
20
- return {
21
- MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
22
- MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
23
- MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
24
- };
25
- }
26
- export function createMockRegistryContract(overrides = {}) {
27
- const filters = {
28
- MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
29
- MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
30
- MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
31
- };
32
- const baseContract = {
33
- minMembershipRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.minRate)),
34
- maxMembershipRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxRate)),
35
- maxTotalRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxTotalRate)),
36
- currentTotalRateLimit: () => Promise.resolve(ethers.BigNumber.from(mockRateLimits.currentTotalRate)),
37
- queryFilter: () => [],
38
- provider: createMockProvider(),
39
- filters,
40
- on: () => ({}),
41
- removeAllListeners: () => ({}),
42
- register: () => ({
43
- wait: () => Promise.resolve({
44
- events: [mockRLNRegisteredEvent()]
45
- })
46
- }),
47
- estimateGas: {
48
- register: () => Promise.resolve(ethers.BigNumber.from(100000))
49
- },
50
- functions: {
51
- register: () => Promise.resolve()
52
- },
53
- getMemberIndex: () => Promise.resolve(null),
54
- interface: {
55
- getEvent: (eventName) => ({
56
- name: eventName,
57
- format: () => { }
58
- })
59
- },
60
- address: LINEA_CONTRACT.address
61
- };
62
- // Merge overrides while preserving filters
63
- const merged = {
64
- ...baseContract,
65
- ...overrides,
66
- filters: { ...filters, ...(overrides.filters || {}) }
67
- };
68
- return merged;
69
- }
70
- export function mockRLNRegisteredEvent(idCommitment) {
71
- return {
72
- args: {
73
- idCommitment: idCommitment ||
74
- "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
75
- membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
76
- index: ethers.BigNumber.from(1)
77
- },
78
- event: "MembershipRegistered"
79
- };
80
- }
81
- export function formatIdCommitment(idCommitmentBigInt) {
82
- return "0x" + idCommitmentBigInt.toString(16).padStart(64, "0");
83
- }
84
- export function createRegisterStub(identity) {
85
- return sinon.stub().callsFake(() => ({
86
- wait: () => Promise.resolve({
87
- events: [
88
- {
89
- event: "MembershipRegistered",
90
- args: {
91
- idCommitment: formatIdCommitment(identity.IDCommitmentBigInt),
92
- membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
93
- index: ethers.BigNumber.from(1)
94
- }
95
- }
96
- ]
97
- })
98
- }));
99
- }
100
- export function verifyRegistration(decryptedCredentials, identity, registerStub, insertMemberSpy) {
101
- if (!decryptedCredentials) {
102
- throw new Error("Decrypted credentials should not be undefined");
103
- }
104
- // Verify registration call
105
- expect(registerStub.calledWith(sinon.match.same(identity.IDCommitmentBigInt), sinon.match.same(DEFAULT_RATE_LIMIT), sinon.match.array, sinon.match.object)).to.be.true;
106
- // Verify credential properties
107
- expect(decryptedCredentials).to.have.property("identity");
108
- expect(decryptedCredentials).to.have.property("membership");
109
- expect(decryptedCredentials.membership).to.include({
110
- address: LINEA_CONTRACT.address,
111
- treeIndex: 1
112
- });
113
- // Verify member insertion
114
- const expectedIdCommitment = ethers.utils.zeroPad(hexToBytes(formatIdCommitment(identity.IDCommitmentBigInt)), 32);
115
- expect(insertMemberSpy.callCount).to.equal(1);
116
- expect(insertMemberSpy.getCall(0).args[0]).to.deep.equal(expectedIdCommitment);
117
- }
118
- //# sourceMappingURL=test-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/contract/test-utils.ts"],"names":[],"mappings":"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"}