@waku/rln 0.1.8-e224c05.0 → 0.1.8-e800af3.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 (187) hide show
  1. package/bundle/_virtual/utils.js +2 -2
  2. package/bundle/_virtual/utils2.js +2 -2
  3. package/bundle/index.js +6 -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/node_modules/@chainsafe/is-ip/lib/is-ip.js +12 -0
  14. package/bundle/node_modules/@chainsafe/is-ip/lib/parse.js +26 -0
  15. package/bundle/node_modules/@chainsafe/is-ip/lib/parser.js +202 -0
  16. package/bundle/node_modules/@multiformats/multiaddr/dist/src/constants.js +43 -0
  17. package/bundle/node_modules/@multiformats/multiaddr/dist/src/errors.js +17 -0
  18. package/bundle/node_modules/@multiformats/multiaddr/dist/src/registry.js +245 -0
  19. package/bundle/node_modules/@multiformats/multiaddr/dist/src/utils.js +191 -0
  20. package/bundle/node_modules/@multiformats/multiaddr/dist/src/validation.js +30 -0
  21. package/bundle/node_modules/@noble/hashes/esm/hmac.js +88 -0
  22. package/bundle/node_modules/@noble/hashes/esm/sha3.js +1 -1
  23. package/bundle/node_modules/@noble/hashes/esm/utils.js +8 -1
  24. package/bundle/node_modules/@waku/zerokit-rln-wasm/rln_wasm.js +517 -255
  25. package/bundle/node_modules/it-length-prefixed/dist/src/decode.js +6 -0
  26. package/bundle/node_modules/multiformats/dist/src/bases/base10.js +3 -1
  27. package/bundle/node_modules/multiformats/dist/src/bases/base16.js +4 -2
  28. package/bundle/node_modules/multiformats/dist/src/bases/base2.js +3 -1
  29. package/bundle/node_modules/multiformats/dist/src/bases/base256emoji.js +3 -1
  30. package/bundle/node_modules/multiformats/dist/src/bases/base32.js +11 -9
  31. package/bundle/node_modules/multiformats/dist/src/bases/base36.js +4 -2
  32. package/bundle/node_modules/multiformats/dist/src/bases/base58.js +4 -2
  33. package/bundle/node_modules/multiformats/dist/src/bases/base64.js +6 -4
  34. package/bundle/node_modules/multiformats/dist/src/bases/base8.js +3 -1
  35. package/bundle/node_modules/multiformats/dist/src/bases/identity.js +3 -1
  36. package/bundle/node_modules/multiformats/dist/src/basics.js +15 -0
  37. package/bundle/node_modules/multiformats/dist/src/bytes.js +15 -1
  38. package/bundle/node_modules/multiformats/dist/src/cid.js +371 -0
  39. package/bundle/node_modules/multiformats/dist/src/hashes/digest.js +62 -0
  40. package/bundle/node_modules/multiformats/dist/src/varint.js +15 -0
  41. package/bundle/node_modules/multiformats/dist/src/vendor/varint.js +78 -0
  42. package/bundle/node_modules/protons-runtime/dist/src/codec.js +20 -0
  43. package/bundle/node_modules/protons-runtime/dist/src/codecs/enum.js +24 -0
  44. package/bundle/node_modules/protons-runtime/dist/src/codecs/message.js +7 -0
  45. package/bundle/node_modules/protons-runtime/dist/src/decode.js +8 -0
  46. package/bundle/node_modules/protons-runtime/dist/src/encode.js +11 -0
  47. package/bundle/node_modules/protons-runtime/dist/src/index.js +30 -0
  48. package/bundle/node_modules/protons-runtime/dist/src/utils/float.js +54 -0
  49. package/bundle/node_modules/protons-runtime/dist/src/utils/longbits.js +175 -0
  50. package/bundle/node_modules/protons-runtime/dist/src/utils/pool.js +28 -0
  51. package/bundle/node_modules/protons-runtime/dist/src/utils/reader.js +367 -0
  52. package/bundle/node_modules/protons-runtime/dist/src/utils/utf8.js +99 -0
  53. package/bundle/node_modules/protons-runtime/dist/src/utils/writer.js +438 -0
  54. package/bundle/node_modules/uint8-varint/dist/src/index.js +124 -0
  55. package/bundle/node_modules/uint8arrays/dist/src/alloc.js +17 -0
  56. package/bundle/node_modules/uint8arrays/dist/src/concat.js +20 -0
  57. package/bundle/node_modules/uint8arrays/dist/src/from-string.js +19 -0
  58. package/bundle/node_modules/uint8arrays/dist/src/to-string.js +19 -0
  59. package/bundle/node_modules/uint8arrays/dist/src/util/as-uint8array.js +9 -0
  60. package/bundle/node_modules/uint8arrays/dist/src/util/bases.js +49 -0
  61. package/bundle/packages/core/dist/lib/connection_manager/connection_limiter.js +18 -0
  62. package/bundle/packages/core/dist/lib/connection_manager/connection_manager.js +24 -0
  63. package/bundle/packages/core/dist/lib/connection_manager/dialer.js +14 -0
  64. package/bundle/packages/core/dist/lib/connection_manager/discovery_dialer.js +14 -0
  65. package/bundle/packages/core/dist/lib/connection_manager/keep_alive_manager.js +15 -0
  66. package/bundle/packages/core/dist/lib/connection_manager/shard_reader.js +14 -0
  67. package/bundle/packages/core/dist/lib/filter/filter.js +28 -0
  68. package/bundle/packages/core/dist/lib/light_push/light_push.js +28 -0
  69. package/bundle/packages/core/dist/lib/message/version_0.js +172 -0
  70. package/bundle/packages/core/dist/lib/metadata/metadata.js +28 -0
  71. package/bundle/packages/core/dist/lib/store/store.js +24 -0
  72. package/bundle/packages/interfaces/dist/connection_manager.js +9 -0
  73. package/bundle/packages/interfaces/dist/health_status.js +17 -0
  74. package/bundle/packages/interfaces/dist/protocols.js +92 -0
  75. package/bundle/packages/interfaces/dist/waku.js +7 -0
  76. package/bundle/packages/proto/dist/generated/filter.js +447 -0
  77. package/bundle/packages/proto/dist/generated/filter_v2.js +426 -0
  78. package/bundle/packages/proto/dist/generated/light_push.js +550 -0
  79. package/bundle/packages/proto/dist/generated/message.js +215 -0
  80. package/bundle/packages/proto/dist/generated/metadata.js +132 -0
  81. package/bundle/packages/proto/dist/generated/peer_exchange.js +211 -0
  82. package/bundle/packages/proto/dist/generated/sds_message.js +172 -0
  83. package/bundle/packages/proto/dist/generated/store_v3.js +492 -0
  84. package/bundle/packages/proto/dist/generated/topic_only_message.js +63 -0
  85. package/bundle/packages/rln/dist/codec.js +92 -0
  86. package/bundle/packages/rln/dist/contract/constants.js +14 -7
  87. package/bundle/packages/rln/dist/contract/rln_base_contract.js +2 -1
  88. package/bundle/packages/rln/dist/contract/rln_contract.js +109 -0
  89. package/bundle/packages/rln/dist/credentials_manager.js +45 -4
  90. package/bundle/packages/rln/dist/identity.js +2 -1
  91. package/bundle/packages/rln/dist/keystore/keystore.js +30 -9
  92. package/bundle/packages/rln/dist/message.js +59 -0
  93. package/bundle/packages/rln/dist/proof.js +54 -0
  94. package/bundle/packages/rln/dist/resources/verification_key.js +112 -0
  95. package/bundle/packages/rln/dist/resources/witness_calculator.js +1 -1
  96. package/bundle/packages/rln/dist/rln.js +36 -4
  97. package/bundle/packages/rln/dist/root_tracker.js +76 -0
  98. package/bundle/packages/rln/dist/utils/bytes.js +70 -31
  99. package/bundle/packages/rln/dist/utils/epoch.js +23 -1
  100. package/bundle/packages/rln/dist/utils/hash.js +10 -0
  101. package/bundle/packages/rln/dist/zerokit.js +99 -2
  102. package/bundle/packages/utils/dist/bytes/index.js +31 -0
  103. package/bundle/resources/rln.wasm +0 -0
  104. package/bundle/resources/rln_final.zkey +0 -0
  105. package/bundle/resources/verification_key.d.ts +13 -0
  106. package/bundle/resources/verification_key.js +112 -0
  107. package/bundle/resources/witness_calculator.d.ts +7 -21
  108. package/bundle/resources/witness_calculator.js +1 -1
  109. package/dist/.tsbuildinfo +1 -1
  110. package/dist/codec.d.ts +40 -0
  111. package/dist/codec.js +79 -0
  112. package/dist/codec.js.map +1 -0
  113. package/dist/codec.test-utils.d.ts +37 -0
  114. package/dist/codec.test-utils.js +61 -0
  115. package/dist/codec.test-utils.js.map +1 -0
  116. package/dist/contract/constants.d.ts +10 -3
  117. package/dist/contract/constants.js +13 -6
  118. package/dist/contract/constants.js.map +1 -1
  119. package/dist/contract/index.d.ts +1 -0
  120. package/dist/contract/index.js +1 -0
  121. package/dist/contract/index.js.map +1 -1
  122. package/dist/contract/rln_base_contract.js +2 -1
  123. package/dist/contract/rln_base_contract.js.map +1 -1
  124. package/dist/contract/rln_contract.d.ts +17 -0
  125. package/dist/contract/rln_contract.js +107 -0
  126. package/dist/contract/rln_contract.js.map +1 -0
  127. package/dist/contract/test_setup.d.ts +26 -0
  128. package/dist/contract/test_setup.js +56 -0
  129. package/dist/contract/test_setup.js.map +1 -0
  130. package/dist/contract/test_utils.d.ts +39 -0
  131. package/dist/contract/test_utils.js +118 -0
  132. package/dist/contract/test_utils.js.map +1 -0
  133. package/dist/credentials_manager.d.ts +14 -2
  134. package/dist/credentials_manager.js +45 -4
  135. package/dist/credentials_manager.js.map +1 -1
  136. package/dist/identity.js +2 -1
  137. package/dist/identity.js.map +1 -1
  138. package/dist/index.d.ts +6 -2
  139. package/dist/index.js +6 -2
  140. package/dist/index.js.map +1 -1
  141. package/dist/keystore/keystore.js +30 -9
  142. package/dist/keystore/keystore.js.map +1 -1
  143. package/dist/message.d.ts +19 -0
  144. package/dist/message.js +51 -0
  145. package/dist/message.js.map +1 -0
  146. package/dist/proof.d.ts +21 -0
  147. package/dist/proof.js +50 -0
  148. package/dist/proof.js.map +1 -0
  149. package/dist/resources/rln.wasm +0 -0
  150. package/dist/resources/rln_final.zkey +0 -0
  151. package/dist/resources/verification_key.d.ts +13 -0
  152. package/dist/resources/verification_key.js +112 -0
  153. package/dist/resources/witness_calculator.d.ts +7 -21
  154. package/dist/resources/witness_calculator.js +1 -1
  155. package/dist/rln.d.ts +9 -0
  156. package/dist/rln.js +32 -4
  157. package/dist/rln.js.map +1 -1
  158. package/dist/root_tracker.d.ts +10 -0
  159. package/dist/root_tracker.js +75 -0
  160. package/dist/root_tracker.js.map +1 -0
  161. package/dist/utils/bytes.d.ts +31 -9
  162. package/dist/utils/bytes.js +70 -31
  163. package/dist/utils/bytes.js.map +1 -1
  164. package/dist/zerokit.d.ts +11 -0
  165. package/dist/zerokit.js +97 -1
  166. package/dist/zerokit.js.map +1 -1
  167. package/package.json +1 -1
  168. package/src/codec.test-utils.ts +88 -0
  169. package/src/codec.ts +138 -0
  170. package/src/contract/constants.ts +16 -6
  171. package/src/contract/index.ts +1 -0
  172. package/src/contract/rln_base_contract.ts +2 -1
  173. package/src/contract/rln_contract.ts +147 -0
  174. package/src/contract/test_setup.ts +86 -0
  175. package/src/contract/test_utils.ts +179 -0
  176. package/src/credentials_manager.ts +72 -8
  177. package/src/identity.ts +2 -1
  178. package/src/index.ts +11 -1
  179. package/src/keystore/keystore.ts +32 -9
  180. package/src/message.ts +73 -0
  181. package/src/proof.ts +69 -0
  182. package/src/resources/verification_key.d.ts +13 -0
  183. package/src/resources/witness_calculator.d.ts +7 -21
  184. package/src/rln.ts +65 -5
  185. package/src/root_tracker.ts +92 -0
  186. package/src/utils/bytes.ts +73 -36
  187. package/src/zerokit.ts +217 -1
package/dist/zerokit.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import * as zerokitRLN from "@waku/zerokit-rln-wasm";
2
- import { DEFAULT_RATE_LIMIT } from "./contract/constants.js";
2
+ import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from "./contract/constants.js";
3
3
  import { IdentityCredential } from "./identity.js";
4
+ import { Proof, proofToBytes } from "./proof.js";
5
+ import { BytesUtils, dateToEpoch, epochIntToBytes } from "./utils/index.js";
4
6
  export class Zerokit {
5
7
  zkRLN;
6
8
  witnessCalculator;
@@ -19,11 +21,105 @@ export class Zerokit {
19
21
  get rateLimit() {
20
22
  return this._rateLimit;
21
23
  }
24
+ generateIdentityCredentials() {
25
+ const memKeys = zerokitRLN.generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm
26
+ return IdentityCredential.fromBytes(memKeys);
27
+ }
22
28
  generateSeededIdentityCredential(seed) {
23
29
  const stringEncoder = new TextEncoder();
24
30
  const seedBytes = stringEncoder.encode(seed);
31
+ // TODO: rename this function in zerokit rln-wasm
25
32
  const memKeys = zerokitRLN.generateSeededExtendedMembershipKey(this.zkRLN, seedBytes);
26
33
  return IdentityCredential.fromBytes(memKeys);
27
34
  }
35
+ insertMember(idCommitment) {
36
+ zerokitRLN.insertMember(this.zkRLN, idCommitment);
37
+ }
38
+ insertMembers(index, ...idCommitments) {
39
+ // serializes a seq of IDCommitments to a byte seq
40
+ // the order of serialization is |id_commitment_len<8>|id_commitment<var>|
41
+ const idCommitmentLen = BytesUtils.writeUIntLE(new Uint8Array(8), idCommitments.length, 0, 8);
42
+ const idCommitmentBytes = BytesUtils.concatenate(idCommitmentLen, ...idCommitments);
43
+ zerokitRLN.setLeavesFrom(this.zkRLN, index, idCommitmentBytes);
44
+ }
45
+ deleteMember(index) {
46
+ zerokitRLN.deleteLeaf(this.zkRLN, index);
47
+ }
48
+ getMerkleRoot() {
49
+ return zerokitRLN.getRoot(this.zkRLN);
50
+ }
51
+ serializeMessage(uint8Msg, memIndex, epoch, idKey, rateLimit) {
52
+ // calculate message length
53
+ const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), uint8Msg.length, 0, 8);
54
+ const memIndexBytes = BytesUtils.writeUIntLE(new Uint8Array(8), memIndex, 0, 8);
55
+ const rateLimitBytes = BytesUtils.writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
56
+ // [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> | rate_limit<8> ]
57
+ return BytesUtils.concatenate(idKey, memIndexBytes, epoch, msgLen, uint8Msg, rateLimitBytes);
58
+ }
59
+ async generateRLNProof(msg, index, epoch, idSecretHash, rateLimit) {
60
+ if (epoch === undefined) {
61
+ epoch = epochIntToBytes(dateToEpoch(new Date()));
62
+ }
63
+ else if (epoch instanceof Date) {
64
+ epoch = epochIntToBytes(dateToEpoch(epoch));
65
+ }
66
+ const effectiveRateLimit = rateLimit ?? this.rateLimit;
67
+ if (epoch.length !== 32)
68
+ throw new Error("invalid epoch");
69
+ if (idSecretHash.length !== 32)
70
+ throw new Error("invalid id secret hash");
71
+ if (index < 0)
72
+ throw new Error("index must be >= 0");
73
+ if (effectiveRateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
74
+ effectiveRateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
75
+ throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
76
+ }
77
+ const serialized_msg = this.serializeMessage(msg, index, epoch, idSecretHash, effectiveRateLimit);
78
+ const rlnWitness = zerokitRLN.getSerializedRLNWitness(this.zkRLN, serialized_msg);
79
+ const inputs = zerokitRLN.RLNWitnessToJson(this.zkRLN, rlnWitness);
80
+ const calculatedWitness = await this.witnessCalculator.calculateWitness(inputs, false);
81
+ const proofBytes = zerokitRLN.generate_rln_proof_with_witness(this.zkRLN, calculatedWitness, rlnWitness);
82
+ return new Proof(proofBytes);
83
+ }
84
+ verifyRLNProof(proof, msg, rateLimit) {
85
+ let pBytes;
86
+ if (proof instanceof Uint8Array) {
87
+ pBytes = proof;
88
+ }
89
+ else {
90
+ pBytes = proofToBytes(proof);
91
+ }
92
+ // calculate message length
93
+ const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
94
+ const rateLimitBytes = BytesUtils.writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
95
+ return zerokitRLN.verifyRLNProof(this.zkRLN, BytesUtils.concatenate(pBytes, msgLen, msg, rateLimitBytes));
96
+ }
97
+ verifyWithRoots(proof, msg, roots, rateLimit) {
98
+ let pBytes;
99
+ if (proof instanceof Uint8Array) {
100
+ pBytes = proof;
101
+ }
102
+ else {
103
+ pBytes = proofToBytes(proof);
104
+ }
105
+ // calculate message length
106
+ const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
107
+ const rateLimitBytes = BytesUtils.writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
108
+ const rootsBytes = BytesUtils.concatenate(...roots);
109
+ return zerokitRLN.verifyWithRoots(this.zkRLN, BytesUtils.concatenate(pBytes, msgLen, msg, rateLimitBytes), rootsBytes);
110
+ }
111
+ verifyWithNoRoot(proof, msg, rateLimit) {
112
+ let pBytes;
113
+ if (proof instanceof Uint8Array) {
114
+ pBytes = proof;
115
+ }
116
+ else {
117
+ pBytes = proofToBytes(proof);
118
+ }
119
+ // calculate message length
120
+ const msgLen = BytesUtils.writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
121
+ const rateLimitBytes = BytesUtils.writeUIntLE(new Uint8Array(8), rateLimit ?? this.rateLimit, 0, 8);
122
+ return zerokitRLN.verifyWithRoots(this.zkRLN, BytesUtils.concatenate(pBytes, msgLen, msg, rateLimitBytes), new Uint8Array());
123
+ }
28
124
  }
29
125
  //# sourceMappingURL=zerokit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zerokit.js","sourceRoot":"","sources":["../src/zerokit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,MAAM,OAAO,OAAO;IAEC;IACA;IACA;IAHnB,YACmB,KAAa,EACb,iBAAoC,EACpC,aAAqB,kBAAkB;QAFvC,UAAK,GAAL,KAAK,CAAQ;QACb,sBAAiB,GAAjB,iBAAiB,CAAmB;QACpC,eAAU,GAAV,UAAU,CAA6B;IACvD,CAAC;IAEJ,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAW,oBAAoB;QAC7B,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAEM,gCAAgC,CAAC,IAAY;QAClD,MAAM,aAAa,GAAG,IAAI,WAAW,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,UAAU,CAAC,mCAAmC,CAC5D,IAAI,CAAC,KAAK,EACV,SAAS,CACV,CAAC;QACF,OAAO,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;CACF"}
1
+ {"version":3,"file":"zerokit.js","sourceRoot":"","sources":["../src/zerokit.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@waku/rln","version":"0.1.8-e224c05.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":">=22"},"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.33-e224c05.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.36-e224c05.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.38-e224c05.0","@waku/utils":"0.0.26-e224c05.0","@noble/hashes":"^1.2.0","@waku/zerokit-rln-wasm":"^0.2.1","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.8-e800af3.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":">=22"},"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.33-e800af3.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.36-e800af3.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.38-e800af3.0","@waku/utils":"0.0.26-e800af3.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"}}
@@ -0,0 +1,88 @@
1
+ import type { IProtoMessage } from "@waku/interfaces";
2
+ import { createRoutingInfo } from "@waku/utils";
3
+ import { expect } from "chai";
4
+
5
+ import { createRLN } from "./create.js";
6
+ import type { IdentityCredential } from "./identity.js";
7
+
8
+ export interface TestRLNCodecSetup {
9
+ rlnInstance: any;
10
+ credential: IdentityCredential;
11
+ index: number;
12
+ payload: Uint8Array;
13
+ }
14
+
15
+ export const TEST_CONSTANTS = {
16
+ contentTopic: "/test/1/waku-message/utf8",
17
+ emptyPubsubTopic: "",
18
+ defaultIndex: 0,
19
+ defaultPayload: new Uint8Array([1, 2, 3, 4, 5]),
20
+ routingInfo: createRoutingInfo(
21
+ {
22
+ clusterId: 0,
23
+ numShardsInCluster: 2
24
+ },
25
+ { contentTopic: "/test/1/waku-message/utf8" }
26
+ )
27
+ } as const;
28
+
29
+ export const EMPTY_PROTO_MESSAGE = {
30
+ timestamp: undefined,
31
+ contentTopic: "",
32
+ ephemeral: undefined,
33
+ meta: undefined,
34
+ rateLimitProof: undefined,
35
+ version: undefined
36
+ } as const;
37
+
38
+ /**
39
+ * Creates a basic RLN setup for codec tests
40
+ */
41
+ export async function createTestRLNCodecSetup(): Promise<TestRLNCodecSetup> {
42
+ const rlnInstance = await createRLN();
43
+ const credential = rlnInstance.zerokit.generateIdentityCredentials();
44
+ rlnInstance.zerokit.insertMember(credential.IDCommitment);
45
+
46
+ return {
47
+ rlnInstance,
48
+ credential,
49
+ index: TEST_CONSTANTS.defaultIndex,
50
+ payload: TEST_CONSTANTS.defaultPayload
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Creates a meta setter function for testing
56
+ */
57
+ export function createTestMetaSetter(): (
58
+ msg: IProtoMessage & { meta: undefined }
59
+ ) => Uint8Array {
60
+ return (msg: IProtoMessage & { meta: undefined }): Uint8Array => {
61
+ const buffer = new ArrayBuffer(4);
62
+ const view = new DataView(buffer);
63
+ view.setUint32(0, msg.payload.length, false);
64
+ return new Uint8Array(buffer);
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Verifies common RLN message properties
70
+ */
71
+ export function verifyRLNMessage(
72
+ msg: any,
73
+ payload: Uint8Array,
74
+ contentTopic: string,
75
+ version: number,
76
+ rlnInstance: any
77
+ ): void {
78
+ expect(msg.rateLimitProof).to.not.be.undefined;
79
+ expect(msg.verify([rlnInstance.zerokit.getMerkleRoot()])).to.be.true;
80
+ expect(msg.verifyNoRoot()).to.be.true;
81
+ expect(msg.epoch).to.not.be.undefined;
82
+ expect(msg.epoch).to.be.gt(0);
83
+
84
+ expect(msg.contentTopic).to.eq(contentTopic);
85
+ expect(msg.msg.version).to.eq(version);
86
+ expect(msg.payload).to.deep.eq(payload);
87
+ expect(msg.timestamp).to.not.be.undefined;
88
+ }
package/src/codec.ts ADDED
@@ -0,0 +1,138 @@
1
+ import type {
2
+ IDecodedMessage,
3
+ IDecoder,
4
+ IEncoder,
5
+ IMessage,
6
+ IProtoMessage,
7
+ IRateLimitProof,
8
+ IRoutingInfo
9
+ } from "@waku/interfaces";
10
+ import { Logger } from "@waku/utils";
11
+
12
+ import type { IdentityCredential } from "./identity.js";
13
+ import { RlnMessage, toRLNSignal } from "./message.js";
14
+ import { RLNInstance } from "./rln.js";
15
+
16
+ const log = new Logger("waku:rln:encoder");
17
+
18
+ export class RLNEncoder implements IEncoder {
19
+ private readonly idSecretHash: Uint8Array;
20
+
21
+ public constructor(
22
+ private readonly encoder: IEncoder,
23
+ private readonly rlnInstance: RLNInstance,
24
+ private readonly index: number,
25
+ identityCredential: IdentityCredential
26
+ ) {
27
+ if (index < 0) throw new Error("Invalid membership index");
28
+ this.idSecretHash = identityCredential.IDSecretHash;
29
+ }
30
+
31
+ public async toWire(message: IMessage): Promise<Uint8Array | undefined> {
32
+ message.rateLimitProof = await this.generateProof(message);
33
+ log.info("Proof generated", message.rateLimitProof);
34
+ return this.encoder.toWire(message);
35
+ }
36
+
37
+ public async toProtoObj(
38
+ message: IMessage
39
+ ): Promise<IProtoMessage | undefined> {
40
+ const protoMessage = await this.encoder.toProtoObj(message);
41
+ if (!protoMessage) return;
42
+
43
+ protoMessage.contentTopic = this.contentTopic;
44
+ protoMessage.rateLimitProof = await this.generateProof(message);
45
+ log.info("Proof generated", protoMessage.rateLimitProof);
46
+ return protoMessage;
47
+ }
48
+
49
+ private async generateProof(message: IMessage): Promise<IRateLimitProof> {
50
+ const signal = toRLNSignal(this.contentTopic, message);
51
+ return this.rlnInstance.zerokit.generateRLNProof(
52
+ signal,
53
+ this.index,
54
+ message.timestamp,
55
+ this.idSecretHash
56
+ );
57
+ }
58
+
59
+ public get pubsubTopic(): string {
60
+ return this.encoder.pubsubTopic;
61
+ }
62
+
63
+ public get routingInfo(): IRoutingInfo {
64
+ return this.encoder.routingInfo;
65
+ }
66
+
67
+ public get contentTopic(): string {
68
+ return this.encoder.contentTopic;
69
+ }
70
+
71
+ public get ephemeral(): boolean {
72
+ return this.encoder.ephemeral;
73
+ }
74
+ }
75
+
76
+ type RLNEncoderOptions = {
77
+ encoder: IEncoder;
78
+ rlnInstance: RLNInstance;
79
+ index: number;
80
+ credential: IdentityCredential;
81
+ };
82
+
83
+ export const createRLNEncoder = (options: RLNEncoderOptions): RLNEncoder => {
84
+ return new RLNEncoder(
85
+ options.encoder,
86
+ options.rlnInstance,
87
+ options.index,
88
+ options.credential
89
+ );
90
+ };
91
+
92
+ export class RLNDecoder<T extends IDecodedMessage>
93
+ implements IDecoder<RlnMessage<T>>
94
+ {
95
+ public constructor(
96
+ private readonly rlnInstance: RLNInstance,
97
+ private readonly decoder: IDecoder<T>
98
+ ) {}
99
+
100
+ public get pubsubTopic(): string {
101
+ return this.decoder.pubsubTopic;
102
+ }
103
+
104
+ public get contentTopic(): string {
105
+ return this.decoder.contentTopic;
106
+ }
107
+
108
+ public fromWireToProtoObj(
109
+ bytes: Uint8Array
110
+ ): Promise<IProtoMessage | undefined> {
111
+ const protoMessage = this.decoder.fromWireToProtoObj(bytes);
112
+ log.info("Message decoded", protoMessage);
113
+ return Promise.resolve(protoMessage);
114
+ }
115
+
116
+ public async fromProtoObj(
117
+ pubsubTopic: string,
118
+ proto: IProtoMessage
119
+ ): Promise<RlnMessage<T> | undefined> {
120
+ const msg: T | undefined = await this.decoder.fromProtoObj(
121
+ pubsubTopic,
122
+ proto
123
+ );
124
+ if (!msg) return;
125
+ return new RlnMessage(this.rlnInstance, msg, proto.rateLimitProof);
126
+ }
127
+ }
128
+
129
+ type RLNDecoderOptions<T extends IDecodedMessage> = {
130
+ decoder: IDecoder<T>;
131
+ rlnInstance: RLNInstance;
132
+ };
133
+
134
+ export const createRLNDecoder = <T extends IDecodedMessage>(
135
+ options: RLNDecoderOptions<T>
136
+ ): RLNDecoder<T> => {
137
+ return new RLNDecoder(options.rlnInstance, options.decoder);
138
+ };
@@ -19,16 +19,26 @@ export const PRICE_CALCULATOR_CONTRACT = {
19
19
  * @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
20
20
  */
21
21
  export const RATE_LIMIT_TIERS = {
22
- STANDARD: 300,
23
- MAX: 600
22
+ LOW: 20, // Suggested minimum rate - 20 messages per epoch
23
+ MEDIUM: 200,
24
+ HIGH: 600 // Suggested maximum rate - 600 messages per epoch
24
25
  } as const;
25
26
 
26
27
  // Global rate limit parameters
27
28
  export const RATE_LIMIT_PARAMS = {
28
- MIN_RATE: RATE_LIMIT_TIERS.STANDARD,
29
- MAX_RATE: RATE_LIMIT_TIERS.MAX,
30
- MAX_TOTAL_RATE: 160_000,
31
- EPOCH_LENGTH: 600
29
+ MIN_RATE: RATE_LIMIT_TIERS.LOW,
30
+ MAX_RATE: RATE_LIMIT_TIERS.HIGH,
31
+ MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
32
+ EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
32
33
  } as const;
33
34
 
35
+ /**
36
+ * Default Q value for the RLN contract
37
+ * This is the upper bound for the ID commitment
38
+ * @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
39
+ */
40
+ export const RLN_Q = BigInt(
41
+ "21888242871839275222246405745257275088548364400416034343698204186575808495617"
42
+ );
43
+
34
44
  export const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
@@ -1,2 +1,3 @@
1
+ export { RLNContract } from "./rln_contract.js";
1
2
  export * from "./constants.js";
2
3
  export * from "./types.js";
@@ -3,6 +3,7 @@ import { ethers } from "ethers";
3
3
 
4
4
  import { IdentityCredential } from "../identity.js";
5
5
  import { DecryptedCredentials } from "../keystore/types.js";
6
+ import { BytesUtils } from "../utils/bytes.js";
6
7
 
7
8
  import { RLN_ABI } from "./abi/rln.js";
8
9
  import {
@@ -631,7 +632,7 @@ export class RLNBaseContract {
631
632
  permit.v,
632
633
  permit.r,
633
634
  permit.s,
634
- identity.IDCommitmentBigInt,
635
+ BytesUtils.buildBigIntFromUint8ArrayBE(identity.IDCommitment),
635
636
  this.rateLimit,
636
637
  idCommitmentsToErase.map((id) => ethers.BigNumber.from(id))
637
638
  );
@@ -0,0 +1,147 @@
1
+ import { Logger } from "@waku/utils";
2
+ import { hexToBytes } from "@waku/utils/bytes";
3
+ import { ethers } from "ethers";
4
+
5
+ import type { RLNInstance } from "../rln.js";
6
+ import { MerkleRootTracker } from "../root_tracker.js";
7
+ import { BytesUtils } from "../utils/bytes.js";
8
+
9
+ import { RLNBaseContract } from "./rln_base_contract.js";
10
+ import { RLNContractInitOptions } from "./types.js";
11
+
12
+ const log = new Logger("waku:rln:contract");
13
+
14
+ export class RLNContract extends RLNBaseContract {
15
+ private instance: RLNInstance;
16
+ private merkleRootTracker: MerkleRootTracker;
17
+
18
+ /**
19
+ * Asynchronous initializer for RLNContract.
20
+ * Allows injecting a mocked contract for testing purposes.
21
+ */
22
+ public static async init(
23
+ rlnInstance: RLNInstance,
24
+ options: RLNContractInitOptions
25
+ ): Promise<RLNContract> {
26
+ const rlnContract = new RLNContract(rlnInstance, options);
27
+
28
+ return rlnContract;
29
+ }
30
+
31
+ private constructor(
32
+ rlnInstance: RLNInstance,
33
+ options: RLNContractInitOptions
34
+ ) {
35
+ super(options);
36
+
37
+ this.instance = rlnInstance;
38
+
39
+ const initialRoot = rlnInstance.zerokit.getMerkleRoot();
40
+ this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
41
+ }
42
+
43
+ public override processEvents(events: ethers.Event[]): void {
44
+ const toRemoveTable = new Map<number, number[]>();
45
+ const toInsertTable = new Map<number, ethers.Event[]>();
46
+
47
+ events.forEach((evt) => {
48
+ if (!evt.args) {
49
+ return;
50
+ }
51
+
52
+ if (
53
+ evt.event === "MembershipErased" ||
54
+ evt.event === "MembershipExpired"
55
+ ) {
56
+ let index = evt.args.index;
57
+
58
+ if (!index) {
59
+ return;
60
+ }
61
+
62
+ if (typeof index === "number" || typeof index === "string") {
63
+ index = ethers.BigNumber.from(index);
64
+ } else {
65
+ log.error("Index is not a number or string", {
66
+ index,
67
+ event: evt
68
+ });
69
+ return;
70
+ }
71
+
72
+ const toRemoveVal = toRemoveTable.get(evt.blockNumber);
73
+ if (toRemoveVal != undefined) {
74
+ toRemoveVal.push(index.toNumber());
75
+ toRemoveTable.set(evt.blockNumber, toRemoveVal);
76
+ } else {
77
+ toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
78
+ }
79
+ } else if (evt.event === "MembershipRegistered") {
80
+ let eventsPerBlock = toInsertTable.get(evt.blockNumber);
81
+ if (eventsPerBlock == undefined) {
82
+ eventsPerBlock = [];
83
+ }
84
+
85
+ eventsPerBlock.push(evt);
86
+ toInsertTable.set(evt.blockNumber, eventsPerBlock);
87
+ }
88
+ });
89
+
90
+ this.removeMembers(this.instance, toRemoveTable);
91
+ this.insertMembers(this.instance, toInsertTable);
92
+ }
93
+
94
+ private insertMembers(
95
+ rlnInstance: RLNInstance,
96
+ toInsert: Map<number, ethers.Event[]>
97
+ ): void {
98
+ toInsert.forEach((events: ethers.Event[], blockNumber: number) => {
99
+ events.forEach((evt) => {
100
+ if (!evt.args) return;
101
+
102
+ const _idCommitment = evt.args.idCommitment as string;
103
+ let index = evt.args.index;
104
+
105
+ if (!_idCommitment || !index) {
106
+ return;
107
+ }
108
+
109
+ if (typeof index === "number" || typeof index === "string") {
110
+ index = ethers.BigNumber.from(index);
111
+ }
112
+
113
+ const idCommitment = BytesUtils.zeroPadLE(
114
+ hexToBytes(_idCommitment),
115
+ 32
116
+ );
117
+ rlnInstance.zerokit.insertMember(idCommitment);
118
+
119
+ const numericIndex = index.toNumber();
120
+ this._members.set(numericIndex, {
121
+ index,
122
+ idCommitment: _idCommitment
123
+ });
124
+ });
125
+
126
+ const currentRoot = rlnInstance.zerokit.getMerkleRoot();
127
+ this.merkleRootTracker.pushRoot(blockNumber, currentRoot);
128
+ });
129
+ }
130
+
131
+ private removeMembers(
132
+ rlnInstance: RLNInstance,
133
+ toRemove: Map<number, number[]>
134
+ ): void {
135
+ const removeDescending = new Map([...toRemove].reverse());
136
+ removeDescending.forEach((indexes: number[], blockNumber: number) => {
137
+ indexes.forEach((index) => {
138
+ if (this._members.has(index)) {
139
+ this._members.delete(index);
140
+ rlnInstance.zerokit.deleteMember(index);
141
+ }
142
+ });
143
+
144
+ this.merkleRootTracker.backFill(blockNumber);
145
+ });
146
+ }
147
+ }
@@ -0,0 +1,86 @@
1
+ import { hexToBytes } from "@waku/utils/bytes";
2
+ import { ethers } from "ethers";
3
+ import sinon from "sinon";
4
+
5
+ import { createRLN } from "../create.js";
6
+ import type { IdentityCredential } from "../identity.js";
7
+
8
+ import { DEFAULT_RATE_LIMIT, RLN_CONTRACT } from "./constants.js";
9
+ import { RLNContract } from "./rln_contract.js";
10
+
11
+ export interface TestRLNInstance {
12
+ rlnInstance: any;
13
+ identity: IdentityCredential;
14
+ insertMemberSpy: sinon.SinonStub;
15
+ }
16
+
17
+ /**
18
+ * Creates a test RLN instance with basic setup
19
+ */
20
+ export async function createTestRLNInstance(): Promise<TestRLNInstance> {
21
+ const rlnInstance = await createRLN();
22
+ const insertMemberSpy = sinon.stub();
23
+ rlnInstance.zerokit.insertMember = insertMemberSpy;
24
+
25
+ const mockSignature =
26
+ "0xdeb8a6b00a8e404deb1f52d3aa72ed7f60a2ff4484c737eedaef18a0aacb2dfb4d5d74ac39bb71fa358cf2eb390565a35b026cc6272f2010d4351e17670311c21c";
27
+ const identity =
28
+ rlnInstance.zerokit.generateSeededIdentityCredential(mockSignature);
29
+
30
+ return {
31
+ rlnInstance,
32
+ identity,
33
+ insertMemberSpy
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Initializes an RLN contract with the given registry contract
39
+ */
40
+ export async function initializeRLNContract(
41
+ rlnInstance: any,
42
+ mockedRegistryContract: ethers.Contract
43
+ ): Promise<RLNContract> {
44
+ const provider = new ethers.providers.JsonRpcProvider();
45
+ const voidSigner = new ethers.VoidSigner(RLN_CONTRACT.address, provider);
46
+
47
+ const originalRegister = mockedRegistryContract.register;
48
+ (mockedRegistryContract as any).register = function (...args: any[]) {
49
+ const result = originalRegister.apply(this, args);
50
+
51
+ if (args[0] && rlnInstance.zerokit) {
52
+ const idCommitmentBigInt = args[0];
53
+ const idCommitmentHex =
54
+ "0x" + idCommitmentBigInt.toString(16).padStart(64, "0");
55
+ const idCommitment = ethers.utils.zeroPad(
56
+ hexToBytes(idCommitmentHex),
57
+ 32
58
+ );
59
+ rlnInstance.zerokit.insertMember(idCommitment);
60
+ }
61
+
62
+ return result;
63
+ };
64
+
65
+ const contract = await RLNContract.init(rlnInstance, {
66
+ address: RLN_CONTRACT.address,
67
+ signer: voidSigner,
68
+ rateLimit: DEFAULT_RATE_LIMIT,
69
+ contract: mockedRegistryContract
70
+ });
71
+
72
+ return contract;
73
+ }
74
+
75
+ /**
76
+ * Common test message data
77
+ */
78
+ export const TEST_DATA = {
79
+ contentTopic: "/test/1/waku-message/utf8",
80
+ emptyPubsubTopic: "",
81
+ testMessage: Uint8Array.from(
82
+ "Hello World".split("").map((x) => x.charCodeAt(0))
83
+ ),
84
+ mockSignature:
85
+ "0xdeb8a6b00a8e404deb1f52d3aa72ed7f60a2ff4484c737eedaef18a0aacb2dfb4d5d74ac39bb71fa358cf2eb390565a35b026cc6272f2010d4351e17670311c21c"
86
+ };