@waku/rln 0.1.6-2ce706d.0 → 0.1.6-34d4730.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/_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/rln/dist/contract/constants.js +1 -7
  14. package/bundle/packages/rln/dist/contract/rln_base_contract.js +5 -10
  15. package/bundle/packages/rln/dist/credentials_manager.js +14 -16
  16. package/bundle/packages/rln/dist/identity.js +7 -37
  17. package/bundle/packages/rln/dist/keystore/keystore.js +11 -15
  18. package/bundle/packages/rln/dist/utils/bytes.js +16 -14
  19. package/dist/.tsbuildinfo +1 -1
  20. package/dist/contract/constants.d.ts +0 -6
  21. package/dist/contract/constants.js +0 -6
  22. package/dist/contract/constants.js.map +1 -1
  23. package/dist/contract/rln_base_contract.js +5 -10
  24. package/dist/contract/rln_base_contract.js.map +1 -1
  25. package/dist/contract/test-utils.d.ts +39 -0
  26. package/dist/contract/test-utils.js +118 -0
  27. package/dist/contract/test-utils.js.map +1 -0
  28. package/dist/credentials_manager.js +14 -16
  29. package/dist/credentials_manager.js.map +1 -1
  30. package/dist/identity.d.ts +2 -11
  31. package/dist/identity.js +6 -23
  32. package/dist/identity.js.map +1 -1
  33. package/dist/keystore/keystore.js +11 -15
  34. package/dist/keystore/keystore.js.map +1 -1
  35. package/dist/utils/bytes.d.ts +6 -2
  36. package/dist/utils/bytes.js +15 -13
  37. package/dist/utils/bytes.js.map +1 -1
  38. package/dist/utils/index.d.ts +1 -1
  39. package/dist/utils/index.js +1 -1
  40. package/dist/utils/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/contract/constants.ts +0 -9
  43. package/src/contract/rln_base_contract.ts +13 -12
  44. package/src/contract/test-utils.ts +179 -0
  45. package/src/credentials_manager.ts +21 -27
  46. package/src/identity.ts +6 -32
  47. package/src/keystore/keystore.ts +24 -28
  48. package/src/utils/bytes.ts +25 -21
  49. package/src/utils/index.ts +1 -1
@@ -16,12 +16,12 @@ export function concatenate(...input) {
16
16
  }
17
17
  return result;
18
18
  }
19
- export function switchEndianness(bytes) {
20
- return new Uint8Array(bytes.reverse());
21
- }
22
- export function buildBigIntFromUint8ArrayBE(bytes) {
23
- // Interpret bytes as big-endian
24
- return bytes.reduce((acc, byte) => (acc << 8n) + BigInt(byte), 0n);
19
+ // Adapted from https://github.com/feross/buffer
20
+ function checkInt(buf, value, offset, ext, max, min) {
21
+ if (value > max || value < min)
22
+ throw new RangeError('"value" argument is out of bounds');
23
+ if (offset + ext > buf.length)
24
+ throw new RangeError("Index out of range");
25
25
  }
26
26
  export function writeUIntLE(buf, value, offset, byteLength, noAssert) {
27
27
  value = +value;
@@ -39,6 +39,15 @@ export function writeUIntLE(buf, value, offset, byteLength, noAssert) {
39
39
  }
40
40
  return buf;
41
41
  }
42
+ /**
43
+ * Transforms Uint8Array into BigInt
44
+ * @param array: Uint8Array
45
+ * @returns BigInt
46
+ */
47
+ export function buildBigIntFromUint8Array(array, byteOffset = 0) {
48
+ const dataView = new DataView(array.buffer);
49
+ return dataView.getBigUint64(byteOffset, true);
50
+ }
42
51
  /**
43
52
  * Fills with zeros to set length
44
53
  * @param array little endian Uint8Array
@@ -52,11 +61,4 @@ export function zeroPadLE(array, length) {
52
61
  }
53
62
  return result;
54
63
  }
55
- // Adapted from https://github.com/feross/buffer
56
- function checkInt(buf, value, offset, ext, max, min) {
57
- if (value > max || value < min)
58
- throw new RangeError('"value" argument is out of bounds');
59
- if (offset + ext > buf.length)
60
- throw new RangeError("Index out of range");
61
- }
62
64
  //# sourceMappingURL=bytes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../../src/utils/bytes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,GAAG,KAAmB;IAChD,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC;IAC5B,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAAiB;IAC3D,gCAAgC;IAChC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAe,EACf,KAAa,EACb,MAAc,EACd,UAAkB,EAClB,QAAkB;IAElB,KAAK,GAAG,CAAC,KAAK,CAAC;IACf,MAAM,GAAG,MAAM,KAAK,CAAC,CAAC;IACtB,UAAU,GAAG,UAAU,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QACjD,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,CAAC,GAAG,UAAU,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC;QAC1C,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;IACzC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,KAAiB,EAAE,MAAc;IACzD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gDAAgD;AAChD,SAAS,QAAQ,CACf,GAAe,EACf,KAAa,EACb,MAAc,EACd,GAAW,EACX,GAAW,EACX,GAAW;IAEX,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG;QAC5B,MAAM,IAAI,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAC5D,IAAI,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM;QAAE,MAAM,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAC5E,CAAC"}
1
+ {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../../src/utils/bytes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,GAAG,KAAmB;IAChD,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC;IAC5B,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gDAAgD;AAChD,SAAS,QAAQ,CACf,GAAe,EACf,KAAa,EACb,MAAc,EACd,GAAW,EACX,GAAW,EACX,GAAW;IAEX,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG;QAC5B,MAAM,IAAI,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAC5D,IAAI,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM;QAAE,MAAM,IAAI,UAAU,CAAC,oBAAoB,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAe,EACf,KAAa,EACb,MAAc,EACd,UAAkB,EAClB,QAAkB;IAElB,KAAK,GAAG,CAAC,KAAK,CAAC;IACf,MAAM,GAAG,MAAM,KAAK,CAAC,CAAC;IACtB,UAAU,GAAG,UAAU,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QACjD,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,CAAC,GAAG,UAAU,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC;QAC1C,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;IACzC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAiB,EACjB,aAAqB,CAAC;IAEtB,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,OAAO,QAAQ,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,KAAiB,EAAE,MAAc;IACzD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  export { extractMetaMaskSigner } from "./metamask.js";
2
- export { concatenate, writeUIntLE, switchEndianness, zeroPadLE } from "./bytes.js";
2
+ export { concatenate, writeUIntLE, buildBigIntFromUint8Array, zeroPadLE } from "./bytes.js";
3
3
  export { sha256, poseidonHash } from "./hash.js";
4
4
  export { dateToEpoch, epochIntToBytes, epochBytesToInt } from "./epoch.js";
@@ -1,5 +1,5 @@
1
1
  export { extractMetaMaskSigner } from "./metamask.js";
2
- export { concatenate, writeUIntLE, switchEndianness, zeroPadLE } from "./bytes.js";
2
+ export { concatenate, writeUIntLE, buildBigIntFromUint8Array, zeroPadLE } from "./bytes.js";
3
3
  export { sha256, poseidonHash } from "./hash.js";
4
4
  export { dateToEpoch, epochIntToBytes, epochBytesToInt } from "./epoch.js";
5
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACL,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACL,WAAW,EACX,WAAW,EACX,yBAAyB,EACzB,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@waku/rln","version":"0.1.6-2ce706d.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-2ce706d.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-2ce706d.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-2ce706d.0","@waku/utils":"0.0.24-2ce706d.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-34d4730.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-34d4730.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-34d4730.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-34d4730.0","@waku/utils":"0.0.24-34d4730.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,13 +25,4 @@ 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
-
37
28
  export const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
@@ -79,8 +79,7 @@ export class RLNBaseContract {
79
79
  const instance = new RLNBaseContract(options);
80
80
  const [min, max] = await Promise.all([
81
81
  instance.contract.minMembershipRateLimit(),
82
- instance.contract.maxMembershipRateLimit(),
83
- instance.contract.Q()
82
+ instance.contract.maxMembershipRateLimit()
84
83
  ]);
85
84
  instance.minRateLimit = ethers.BigNumber.from(min).toNumber();
86
85
  instance.maxRateLimit = ethers.BigNumber.from(max).toNumber();
@@ -491,6 +490,7 @@ export class RLNBaseContract {
491
490
  log.error(`Error in withdraw: ${(error as Error).message}`);
492
491
  }
493
492
  }
493
+
494
494
  public async registerWithIdentity(
495
495
  identity: IdentityCredential
496
496
  ): Promise<DecryptedCredentials | undefined> {
@@ -499,12 +499,10 @@ export class RLNBaseContract {
499
499
  `Registering identity with rate limit: ${this.rateLimit} messages/epoch`
500
500
  );
501
501
 
502
- const idCommitmentBigInt = IdentityCredential.getIdCommitmentBigInt(
503
- identity.IDCommitment
504
- );
505
-
506
502
  // Check if the ID commitment is already registered
507
- const existingIndex = await this.getMemberIndex(idCommitmentBigInt);
503
+ const existingIndex = await this.getMemberIndex(
504
+ identity.IDCommitmentBigInt
505
+ );
508
506
  if (existingIndex) {
509
507
  throw new Error(
510
508
  `ID commitment is already registered with index ${existingIndex}`
@@ -520,16 +518,19 @@ export class RLNBaseContract {
520
518
  }
521
519
 
522
520
  const estimatedGas = await this.contract.estimateGas.register(
523
- idCommitmentBigInt,
521
+ identity.IDCommitmentBigInt,
524
522
  this.rateLimit,
525
523
  []
526
524
  );
527
525
  const gasLimit = estimatedGas.add(10000);
528
526
 
529
527
  const txRegisterResponse: ethers.ContractTransaction =
530
- await this.contract.register(idCommitmentBigInt, this.rateLimit, [], {
531
- gasLimit
532
- });
528
+ await this.contract.register(
529
+ identity.IDCommitmentBigInt,
530
+ this.rateLimit,
531
+ [],
532
+ { gasLimit }
533
+ );
533
534
 
534
535
  const txRegisterReceipt = await txRegisterResponse.wait();
535
536
 
@@ -625,7 +626,7 @@ export class RLNBaseContract {
625
626
  permit.v,
626
627
  permit.r,
627
628
  permit.s,
628
- IdentityCredential.getIdCommitmentBigInt(identity.IDCommitment),
629
+ identity.IDCommitmentBigInt,
629
630
  this.rateLimit,
630
631
  idCommitmentsToErase.map((id) => ethers.BigNumber.from(id))
631
632
  );
@@ -0,0 +1,179 @@
1
+ import { hexToBytes } from "@waku/utils/bytes";
2
+ import { expect } from "chai";
3
+ import * as ethers from "ethers";
4
+ import sinon from "sinon";
5
+
6
+ import type { IdentityCredential } from "../identity.js";
7
+
8
+ import { DEFAULT_RATE_LIMIT, LINEA_CONTRACT } from "./constants.js";
9
+
10
+ export const mockRateLimits = {
11
+ minRate: 20,
12
+ maxRate: 600,
13
+ maxTotalRate: 1200,
14
+ currentTotalRate: 500
15
+ };
16
+
17
+ type MockProvider = {
18
+ getLogs: () => never[];
19
+ getBlockNumber: () => Promise<number>;
20
+ getNetwork: () => Promise<{ chainId: number }>;
21
+ };
22
+
23
+ type MockFilters = {
24
+ MembershipRegistered: () => { address: string };
25
+ MembershipErased: () => { address: string };
26
+ MembershipExpired: () => { address: string };
27
+ };
28
+
29
+ export function createMockProvider(): MockProvider {
30
+ return {
31
+ getLogs: () => [],
32
+ getBlockNumber: () => Promise.resolve(1000),
33
+ getNetwork: () => Promise.resolve({ chainId: 11155111 })
34
+ };
35
+ }
36
+
37
+ export function createMockFilters(): MockFilters {
38
+ return {
39
+ MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
40
+ MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
41
+ MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
42
+ };
43
+ }
44
+
45
+ type ContractOverrides = Partial<{
46
+ filters: Record<string, unknown>;
47
+ [key: string]: unknown;
48
+ }>;
49
+
50
+ export function createMockRegistryContract(
51
+ overrides: ContractOverrides = {}
52
+ ): ethers.Contract {
53
+ const filters = {
54
+ MembershipRegistered: () => ({ address: LINEA_CONTRACT.address }),
55
+ MembershipErased: () => ({ address: LINEA_CONTRACT.address }),
56
+ MembershipExpired: () => ({ address: LINEA_CONTRACT.address })
57
+ };
58
+
59
+ const baseContract = {
60
+ minMembershipRateLimit: () =>
61
+ Promise.resolve(ethers.BigNumber.from(mockRateLimits.minRate)),
62
+ maxMembershipRateLimit: () =>
63
+ Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxRate)),
64
+ maxTotalRateLimit: () =>
65
+ Promise.resolve(ethers.BigNumber.from(mockRateLimits.maxTotalRate)),
66
+ currentTotalRateLimit: () =>
67
+ Promise.resolve(ethers.BigNumber.from(mockRateLimits.currentTotalRate)),
68
+ queryFilter: () => [],
69
+ provider: createMockProvider(),
70
+ filters,
71
+ on: () => ({}),
72
+ removeAllListeners: () => ({}),
73
+ register: () => ({
74
+ wait: () =>
75
+ Promise.resolve({
76
+ events: [mockRLNRegisteredEvent()]
77
+ })
78
+ }),
79
+ estimateGas: {
80
+ register: () => Promise.resolve(ethers.BigNumber.from(100000))
81
+ },
82
+ functions: {
83
+ register: () => Promise.resolve()
84
+ },
85
+ getMemberIndex: () => Promise.resolve(null),
86
+ interface: {
87
+ getEvent: (eventName: string) => ({
88
+ name: eventName,
89
+ format: () => {}
90
+ })
91
+ },
92
+ address: LINEA_CONTRACT.address
93
+ };
94
+
95
+ // Merge overrides while preserving filters
96
+ const merged = {
97
+ ...baseContract,
98
+ ...overrides,
99
+ filters: { ...filters, ...(overrides.filters || {}) }
100
+ };
101
+
102
+ return merged as unknown as ethers.Contract;
103
+ }
104
+
105
+ export function mockRLNRegisteredEvent(idCommitment?: string): ethers.Event {
106
+ return {
107
+ args: {
108
+ idCommitment:
109
+ idCommitment ||
110
+ "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
111
+ membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
112
+ index: ethers.BigNumber.from(1)
113
+ },
114
+ event: "MembershipRegistered"
115
+ } as unknown as ethers.Event;
116
+ }
117
+
118
+ export function formatIdCommitment(idCommitmentBigInt: bigint): string {
119
+ return "0x" + idCommitmentBigInt.toString(16).padStart(64, "0");
120
+ }
121
+
122
+ export function createRegisterStub(
123
+ identity: IdentityCredential
124
+ ): sinon.SinonStub {
125
+ return sinon.stub().callsFake(() => ({
126
+ wait: () =>
127
+ Promise.resolve({
128
+ events: [
129
+ {
130
+ event: "MembershipRegistered",
131
+ args: {
132
+ idCommitment: formatIdCommitment(identity.IDCommitmentBigInt),
133
+ membershipRateLimit: ethers.BigNumber.from(DEFAULT_RATE_LIMIT),
134
+ index: ethers.BigNumber.from(1)
135
+ }
136
+ }
137
+ ]
138
+ })
139
+ }));
140
+ }
141
+
142
+ export function verifyRegistration(
143
+ decryptedCredentials: any,
144
+ identity: IdentityCredential,
145
+ registerStub: sinon.SinonStub,
146
+ insertMemberSpy: sinon.SinonStub
147
+ ): void {
148
+ if (!decryptedCredentials) {
149
+ throw new Error("Decrypted credentials should not be undefined");
150
+ }
151
+
152
+ // Verify registration call
153
+ expect(
154
+ registerStub.calledWith(
155
+ sinon.match.same(identity.IDCommitmentBigInt),
156
+ sinon.match.same(DEFAULT_RATE_LIMIT),
157
+ sinon.match.array,
158
+ sinon.match.object
159
+ )
160
+ ).to.be.true;
161
+
162
+ // Verify credential properties
163
+ expect(decryptedCredentials).to.have.property("identity");
164
+ expect(decryptedCredentials).to.have.property("membership");
165
+ expect(decryptedCredentials.membership).to.include({
166
+ address: LINEA_CONTRACT.address,
167
+ treeIndex: 1
168
+ });
169
+
170
+ // Verify member insertion
171
+ const expectedIdCommitment = ethers.utils.zeroPad(
172
+ hexToBytes(formatIdCommitment(identity.IDCommitmentBigInt)),
173
+ 32
174
+ );
175
+ expect(insertMemberSpy.callCount).to.equal(1);
176
+ expect(insertMemberSpy.getCall(0).args[0]).to.deep.equal(
177
+ expectedIdCommitment
178
+ );
179
+ }
@@ -1,5 +1,5 @@
1
1
  import { hmac } from "@noble/hashes/hmac";
2
- import { sha256 } from "@noble/hashes/sha2";
2
+ import { sha256 } from "@noble/hashes/sha256";
3
3
  import { Logger } from "@waku/utils";
4
4
  import { ethers } from "ethers";
5
5
 
@@ -13,7 +13,10 @@ 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 { extractMetaMaskSigner, switchEndianness } from "./utils/index.js";
16
+ import {
17
+ buildBigIntFromUint8Array,
18
+ extractMetaMaskSigner
19
+ } from "./utils/index.js";
17
20
  import { Zerokit } from "./zerokit.js";
18
21
 
19
22
  const log = new Logger("waku:credentials");
@@ -113,9 +116,7 @@ export class RLNCredentialsManager {
113
116
  );
114
117
  } else {
115
118
  log.info("Using local implementation to generate identity");
116
- identity = await this.generateSeededIdentityCredential(
117
- options.signature
118
- );
119
+ identity = this.generateSeededIdentityCredential(options.signature);
119
120
  }
120
121
  }
121
122
 
@@ -248,9 +249,7 @@ export class RLNCredentialsManager {
248
249
  * @param seed A string seed to generate the identity from
249
250
  * @returns IdentityCredential
250
251
  */
251
- private async generateSeededIdentityCredential(
252
- seed: string
253
- ): Promise<IdentityCredential> {
252
+ private generateSeededIdentityCredential(seed: string): IdentityCredential {
254
253
  log.info("Generating seeded identity credential");
255
254
  // Convert the seed to bytes
256
255
  const encoder = new TextEncoder();
@@ -258,31 +257,26 @@ export class RLNCredentialsManager {
258
257
 
259
258
  // Generate deterministic values using HMAC-SHA256
260
259
  // We use different context strings for each component to ensure they're different
261
- const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
262
- const idNullifierBE = hmac(
263
- sha256,
264
- seedBytes,
265
- encoder.encode("IDNullifier")
266
- );
260
+ const idTrapdoor = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
261
+ const idNullifier = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
267
262
 
268
- const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
269
- const idSecretHashBE = sha256(combinedBytes);
263
+ // Generate IDSecretHash as a hash of IDTrapdoor and IDNullifier
264
+ const combinedBytes = new Uint8Array([...idTrapdoor, ...idNullifier]);
265
+ const idSecretHash = sha256(combinedBytes);
270
266
 
271
- const idCommitmentBE = sha256(idSecretHashBE);
267
+ // Generate IDCommitment as a hash of IDSecretHash
268
+ const idCommitment = sha256(idSecretHash);
272
269
 
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);
270
+ // Convert IDCommitment to BigInt
271
+ const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment);
279
272
 
280
273
  log.info("Successfully generated identity credential");
281
274
  return new IdentityCredential(
282
- idTrapdoorLE,
283
- idNullifierLE,
284
- idSecretHashLE,
285
- idCommitmentLE
275
+ idTrapdoor,
276
+ idNullifier,
277
+ idSecretHash,
278
+ idCommitment,
279
+ idCommitmentBigInt
286
280
  );
287
281
  }
288
282
  }
package/src/identity.ts CHANGED
@@ -1,19 +1,12 @@
1
- import { Logger } from "@waku/utils";
2
-
3
- import { DEFAULT_Q } from "./contract/constants.js";
4
- import { buildBigIntFromUint8ArrayBE } from "./utils/bytes.js";
5
-
6
- const log = new Logger("waku:rln:identity");
1
+ import { buildBigIntFromUint8Array } from "./utils/index.js";
7
2
 
8
3
  export class IdentityCredential {
9
- /**
10
- * All variables are in little-endian format
11
- */
12
4
  public constructor(
13
5
  public readonly IDTrapdoor: Uint8Array,
14
6
  public readonly IDNullifier: Uint8Array,
15
7
  public readonly IDSecretHash: Uint8Array,
16
- public readonly IDCommitment: Uint8Array
8
+ public readonly IDCommitment: Uint8Array,
9
+ public readonly IDCommitmentBigInt: bigint
17
10
  ) {}
18
11
 
19
12
  public static fromBytes(memKeys: Uint8Array): IdentityCredential {
@@ -25,33 +18,14 @@ export class IdentityCredential {
25
18
  const idNullifier = memKeys.subarray(32, 64);
26
19
  const idSecretHash = memKeys.subarray(64, 96);
27
20
  const idCommitment = memKeys.subarray(96, 128);
21
+ const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment, 32);
28
22
 
29
23
  return new IdentityCredential(
30
24
  idTrapdoor,
31
25
  idNullifier,
32
26
  idSecretHash,
33
- idCommitment
27
+ idCommitment,
28
+ idCommitmentBigInt
34
29
  );
35
30
  }
36
-
37
- /**
38
- * Converts an ID commitment from bytes to a BigInt, normalizing it against a limit if needed
39
- * @param bytes The ID commitment bytes to convert
40
- * @param limit Optional limit to normalize against (Q value)
41
- * @returns The ID commitment as a BigInt
42
- */
43
- public static getIdCommitmentBigInt(
44
- bytes: Uint8Array,
45
- limit: bigint = DEFAULT_Q
46
- ): bigint {
47
- let idCommitmentBigIntBE = buildBigIntFromUint8ArrayBE(bytes);
48
-
49
- if (limit && idCommitmentBigIntBE >= limit) {
50
- log.warn(
51
- `ID commitment is greater than Q, reducing it by Q: ${idCommitmentBigIntBE} % ${limit}`
52
- );
53
- idCommitmentBigIntBE = idCommitmentBigIntBE % limit;
54
- }
55
- return idCommitmentBigIntBE;
56
- }
57
31
  }
@@ -14,6 +14,8 @@ import {
14
14
  import _ from "lodash";
15
15
  import { v4 as uuidV4 } from "uuid";
16
16
 
17
+ import { buildBigIntFromUint8Array } from "../utils/bytes.js";
18
+
17
19
  import { decryptEipKeystore, keccak256Checksum } from "./cipher.js";
18
20
  import { isCredentialValid, isKeystoreValid } from "./schema_validator.js";
19
21
  import type {
@@ -248,25 +250,26 @@ export class Keystore {
248
250
  const str = bytesToUtf8(bytes);
249
251
  const obj = JSON.parse(str);
250
252
 
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
-
253
+ // TODO: add runtime validation of nwaku credentials
264
254
  return {
265
255
  identity: {
266
- IDCommitment: idCommitmentLE,
267
- IDTrapdoor: idTrapdoorLE,
268
- IDNullifier: idNullifierLE,
269
- IDSecretHash: idSecretHashLE
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
+ )
270
273
  },
271
274
  membership: {
272
275
  treeIndex: _.get(obj, "treeIndex"),
@@ -318,21 +321,14 @@ export class Keystore {
318
321
  // follows nwaku implementation
319
322
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
320
323
  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(
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))
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)
336
332
  },
337
333
  membershipContract: {
338
334
  chainId: options.membership.chainId,
@@ -17,13 +17,18 @@ export function concatenate(...input: Uint8Array[]): Uint8Array {
17
17
  return result;
18
18
  }
19
19
 
20
- export function switchEndianness(bytes: Uint8Array): Uint8Array {
21
- return new Uint8Array(bytes.reverse());
22
- }
23
-
24
- export function buildBigIntFromUint8ArrayBE(bytes: Uint8Array): bigint {
25
- // Interpret bytes as big-endian
26
- return bytes.reduce((acc, byte) => (acc << 8n) + BigInt(byte), 0n);
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");
27
32
  }
28
33
 
29
34
  export function writeUIntLE(
@@ -51,6 +56,19 @@ export function writeUIntLE(
51
56
  return buf;
52
57
  }
53
58
 
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
+
54
72
  /**
55
73
  * Fills with zeros to set length
56
74
  * @param array little endian Uint8Array
@@ -64,17 +82,3 @@ export function zeroPadLE(array: Uint8Array, length: number): Uint8Array {
64
82
  }
65
83
  return result;
66
84
  }
67
-
68
- // Adapted from https://github.com/feross/buffer
69
- function checkInt(
70
- buf: Uint8Array,
71
- value: number,
72
- offset: number,
73
- ext: number,
74
- max: number,
75
- min: number
76
- ): void {
77
- if (value > max || value < min)
78
- throw new RangeError('"value" argument is out of bounds');
79
- if (offset + ext > buf.length) throw new RangeError("Index out of range");
80
- }
@@ -2,7 +2,7 @@ export { extractMetaMaskSigner } from "./metamask.js";
2
2
  export {
3
3
  concatenate,
4
4
  writeUIntLE,
5
- switchEndianness,
5
+ buildBigIntFromUint8Array,
6
6
  zeroPadLE
7
7
  } from "./bytes.js";
8
8
  export { sha256, poseidonHash } from "./hash.js";