@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
@@ -0,0 +1,63 @@
1
+ import { decodeMessage } from '../../../../node_modules/protons-runtime/dist/src/decode.js';
2
+ import { encodeMessage } from '../../../../node_modules/protons-runtime/dist/src/encode.js';
3
+ import '../../../../node_modules/protons-runtime/dist/src/codec.js';
4
+ import { message } from '../../../../node_modules/protons-runtime/dist/src/codecs/message.js';
5
+ import '../../../../node_modules/protons-runtime/dist/src/utils/float.js';
6
+ import '../../../../node_modules/protons-runtime/dist/src/utils/longbits.js';
7
+ import '../../../../node_modules/protons-runtime/dist/src/utils/writer.js';
8
+
9
+ /* eslint-disable import/export */
10
+ /* eslint-disable complexity */
11
+ /* eslint-disable @typescript-eslint/no-namespace */
12
+ /* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
13
+ /* eslint-disable @typescript-eslint/no-empty-interface */
14
+ /* eslint-disable import/consistent-type-specifier-style */
15
+ /* eslint-disable @typescript-eslint/no-unused-vars */
16
+ var TopicOnlyMessage;
17
+ (function (TopicOnlyMessage) {
18
+ let _codec;
19
+ TopicOnlyMessage.codec = () => {
20
+ if (_codec == null) {
21
+ _codec = message((obj, w, opts = {}) => {
22
+ if (opts.lengthDelimited !== false) {
23
+ w.fork();
24
+ }
25
+ if ((obj.contentTopic != null && obj.contentTopic !== '')) {
26
+ w.uint32(18);
27
+ w.string(obj.contentTopic);
28
+ }
29
+ if (opts.lengthDelimited !== false) {
30
+ w.ldelim();
31
+ }
32
+ }, (reader, length, opts = {}) => {
33
+ const obj = {
34
+ contentTopic: ''
35
+ };
36
+ const end = length == null ? reader.len : reader.pos + length;
37
+ while (reader.pos < end) {
38
+ const tag = reader.uint32();
39
+ switch (tag >>> 3) {
40
+ case 2: {
41
+ obj.contentTopic = reader.string();
42
+ break;
43
+ }
44
+ default: {
45
+ reader.skipType(tag & 7);
46
+ break;
47
+ }
48
+ }
49
+ }
50
+ return obj;
51
+ });
52
+ }
53
+ return _codec;
54
+ };
55
+ TopicOnlyMessage.encode = (obj) => {
56
+ return encodeMessage(obj, TopicOnlyMessage.codec());
57
+ };
58
+ TopicOnlyMessage.decode = (buf, opts) => {
59
+ return decodeMessage(buf, TopicOnlyMessage.codec(), opts);
60
+ };
61
+ })(TopicOnlyMessage || (TopicOnlyMessage = {}));
62
+
63
+ export { TopicOnlyMessage };
@@ -0,0 +1,92 @@
1
+ import '../../../node_modules/multiformats/dist/src/bases/base10.js';
2
+ import '../../../node_modules/multiformats/dist/src/bases/base16.js';
3
+ import '../../../node_modules/multiformats/dist/src/bases/base2.js';
4
+ import '../../../node_modules/multiformats/dist/src/bases/base256emoji.js';
5
+ import '../../../node_modules/multiformats/dist/src/bases/base32.js';
6
+ import '../../../node_modules/multiformats/dist/src/bases/base36.js';
7
+ import '../../../node_modules/multiformats/dist/src/bases/base58.js';
8
+ import '../../../node_modules/multiformats/dist/src/bases/base64.js';
9
+ import '../../../node_modules/multiformats/dist/src/bases/base8.js';
10
+ import '../../../node_modules/multiformats/dist/src/bases/identity.js';
11
+ import '../../../node_modules/multiformats/dist/src/codecs/json.js';
12
+ import { Logger } from '../../utils/dist/logger.js';
13
+ import { toRLNSignal, RlnMessage } from './message.js';
14
+
15
+ const log = new Logger("waku:rln:encoder");
16
+ class RLNEncoder {
17
+ encoder;
18
+ rlnInstance;
19
+ index;
20
+ idSecretHash;
21
+ constructor(encoder, rlnInstance, index, identityCredential) {
22
+ this.encoder = encoder;
23
+ this.rlnInstance = rlnInstance;
24
+ this.index = index;
25
+ if (index < 0)
26
+ throw new Error("Invalid membership index");
27
+ this.idSecretHash = identityCredential.IDSecretHash;
28
+ }
29
+ async toWire(message) {
30
+ message.rateLimitProof = await this.generateProof(message);
31
+ log.info("Proof generated", message.rateLimitProof);
32
+ return this.encoder.toWire(message);
33
+ }
34
+ async toProtoObj(message) {
35
+ const protoMessage = await this.encoder.toProtoObj(message);
36
+ if (!protoMessage)
37
+ return;
38
+ protoMessage.contentTopic = this.contentTopic;
39
+ protoMessage.rateLimitProof = await this.generateProof(message);
40
+ log.info("Proof generated", protoMessage.rateLimitProof);
41
+ return protoMessage;
42
+ }
43
+ async generateProof(message) {
44
+ const signal = toRLNSignal(this.contentTopic, message);
45
+ return this.rlnInstance.zerokit.generateRLNProof(signal, this.index, message.timestamp, this.idSecretHash);
46
+ }
47
+ get pubsubTopic() {
48
+ return this.encoder.pubsubTopic;
49
+ }
50
+ get routingInfo() {
51
+ return this.encoder.routingInfo;
52
+ }
53
+ get contentTopic() {
54
+ return this.encoder.contentTopic;
55
+ }
56
+ get ephemeral() {
57
+ return this.encoder.ephemeral;
58
+ }
59
+ }
60
+ const createRLNEncoder = (options) => {
61
+ return new RLNEncoder(options.encoder, options.rlnInstance, options.index, options.credential);
62
+ };
63
+ class RLNDecoder {
64
+ rlnInstance;
65
+ decoder;
66
+ constructor(rlnInstance, decoder) {
67
+ this.rlnInstance = rlnInstance;
68
+ this.decoder = decoder;
69
+ }
70
+ get pubsubTopic() {
71
+ return this.decoder.pubsubTopic;
72
+ }
73
+ get contentTopic() {
74
+ return this.decoder.contentTopic;
75
+ }
76
+ fromWireToProtoObj(bytes) {
77
+ const protoMessage = this.decoder.fromWireToProtoObj(bytes);
78
+ log.info("Message decoded", protoMessage);
79
+ return Promise.resolve(protoMessage);
80
+ }
81
+ async fromProtoObj(pubsubTopic, proto) {
82
+ const msg = await this.decoder.fromProtoObj(pubsubTopic, proto);
83
+ if (!msg)
84
+ return;
85
+ return new RlnMessage(this.rlnInstance, msg, proto.rateLimitProof);
86
+ }
87
+ }
88
+ const createRLNDecoder = (options) => {
89
+ return new RLNDecoder(options.rlnInstance, options.decoder);
90
+ };
91
+
92
+ export { RLNDecoder, RLNEncoder, createRLNDecoder, createRLNEncoder };
@@ -17,16 +17,23 @@ const PRICE_CALCULATOR_CONTRACT = {
17
17
  * @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
18
18
  */
19
19
  const RATE_LIMIT_TIERS = {
20
- STANDARD: 300,
21
- MAX: 600
20
+ LOW: 20, // Suggested minimum rate - 20 messages per epoch
21
+ MEDIUM: 200,
22
+ HIGH: 600 // Suggested maximum rate - 600 messages per epoch
22
23
  };
23
24
  // Global rate limit parameters
24
25
  const RATE_LIMIT_PARAMS = {
25
- MIN_RATE: RATE_LIMIT_TIERS.STANDARD,
26
- MAX_RATE: RATE_LIMIT_TIERS.MAX,
27
- MAX_TOTAL_RATE: 160_000,
28
- EPOCH_LENGTH: 600
26
+ MIN_RATE: RATE_LIMIT_TIERS.LOW,
27
+ MAX_RATE: RATE_LIMIT_TIERS.HIGH,
28
+ MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
29
+ EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
29
30
  };
31
+ /**
32
+ * Default Q value for the RLN contract
33
+ * This is the upper bound for the ID commitment
34
+ * @see https://github.com/waku-org/specs/blob/master/standards/core/rln-contract.md#implementation-suggestions
35
+ */
36
+ const RLN_Q = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
30
37
  const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
31
38
 
32
- export { DEFAULT_RATE_LIMIT, PRICE_CALCULATOR_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS, RLN_CONTRACT };
39
+ export { DEFAULT_RATE_LIMIT, PRICE_CALCULATOR_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS, RLN_CONTRACT, RLN_Q };
@@ -10,6 +10,7 @@ import '../../../../node_modules/multiformats/dist/src/bases/base8.js';
10
10
  import '../../../../node_modules/multiformats/dist/src/bases/identity.js';
11
11
  import '../../../../node_modules/multiformats/dist/src/codecs/json.js';
12
12
  import { Logger } from '../../../utils/dist/logger.js';
13
+ import { BytesUtils } from '../utils/bytes.js';
13
14
  import { RLN_ABI } from './abi/rln.js';
14
15
  import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS, PRICE_CALCULATOR_CONTRACT } from './constants.js';
15
16
  import { MembershipState } from './types.js';
@@ -413,7 +414,7 @@ class RLNBaseContract {
413
414
  async registerWithPermitAndErase(identity, permit, idCommitmentsToErase) {
414
415
  try {
415
416
  log.info(`Registering identity with permit and rate limit: ${this.rateLimit} messages/epoch`);
416
- const txRegisterResponse = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, identity.IDCommitmentBigInt, this.rateLimit, idCommitmentsToErase.map((id) => BigNumber.from(id)));
417
+ const txRegisterResponse = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, BytesUtils.buildBigIntFromUint8ArrayBE(identity.IDCommitment), this.rateLimit, idCommitmentsToErase.map((id) => BigNumber.from(id)));
417
418
  const txRegisterReceipt = await txRegisterResponse.wait();
418
419
  const memberRegistered = txRegisterReceipt.events?.find((event) => event.event === "MembershipRegistered");
419
420
  if (!memberRegistered || !memberRegistered.args) {
@@ -0,0 +1,109 @@
1
+ import { hexToBytes } from '../../../utils/dist/bytes/index.js';
2
+ import { Logger } from '../../../utils/dist/logger.js';
3
+ import { MerkleRootTracker } from '../root_tracker.js';
4
+ import { BytesUtils } from '../utils/bytes.js';
5
+ import { RLNBaseContract } from './rln_base_contract.js';
6
+ import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
7
+
8
+ const log = new Logger("waku:rln:contract");
9
+ class RLNContract extends RLNBaseContract {
10
+ instance;
11
+ merkleRootTracker;
12
+ /**
13
+ * Asynchronous initializer for RLNContract.
14
+ * Allows injecting a mocked contract for testing purposes.
15
+ */
16
+ static async init(rlnInstance, options) {
17
+ const rlnContract = new RLNContract(rlnInstance, options);
18
+ return rlnContract;
19
+ }
20
+ constructor(rlnInstance, options) {
21
+ super(options);
22
+ this.instance = rlnInstance;
23
+ const initialRoot = rlnInstance.zerokit.getMerkleRoot();
24
+ this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
25
+ }
26
+ processEvents(events) {
27
+ const toRemoveTable = new Map();
28
+ const toInsertTable = new Map();
29
+ events.forEach((evt) => {
30
+ if (!evt.args) {
31
+ return;
32
+ }
33
+ if (evt.event === "MembershipErased" ||
34
+ evt.event === "MembershipExpired") {
35
+ let index = evt.args.index;
36
+ if (!index) {
37
+ return;
38
+ }
39
+ if (typeof index === "number" || typeof index === "string") {
40
+ index = BigNumber.from(index);
41
+ }
42
+ else {
43
+ log.error("Index is not a number or string", {
44
+ index,
45
+ event: evt
46
+ });
47
+ return;
48
+ }
49
+ const toRemoveVal = toRemoveTable.get(evt.blockNumber);
50
+ if (toRemoveVal != undefined) {
51
+ toRemoveVal.push(index.toNumber());
52
+ toRemoveTable.set(evt.blockNumber, toRemoveVal);
53
+ }
54
+ else {
55
+ toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
56
+ }
57
+ }
58
+ else if (evt.event === "MembershipRegistered") {
59
+ let eventsPerBlock = toInsertTable.get(evt.blockNumber);
60
+ if (eventsPerBlock == undefined) {
61
+ eventsPerBlock = [];
62
+ }
63
+ eventsPerBlock.push(evt);
64
+ toInsertTable.set(evt.blockNumber, eventsPerBlock);
65
+ }
66
+ });
67
+ this.removeMembers(this.instance, toRemoveTable);
68
+ this.insertMembers(this.instance, toInsertTable);
69
+ }
70
+ insertMembers(rlnInstance, toInsert) {
71
+ toInsert.forEach((events, blockNumber) => {
72
+ events.forEach((evt) => {
73
+ if (!evt.args)
74
+ return;
75
+ const _idCommitment = evt.args.idCommitment;
76
+ let index = evt.args.index;
77
+ if (!_idCommitment || !index) {
78
+ return;
79
+ }
80
+ if (typeof index === "number" || typeof index === "string") {
81
+ index = BigNumber.from(index);
82
+ }
83
+ const idCommitment = BytesUtils.zeroPadLE(hexToBytes(_idCommitment), 32);
84
+ rlnInstance.zerokit.insertMember(idCommitment);
85
+ const numericIndex = index.toNumber();
86
+ this._members.set(numericIndex, {
87
+ index,
88
+ idCommitment: _idCommitment
89
+ });
90
+ });
91
+ const currentRoot = rlnInstance.zerokit.getMerkleRoot();
92
+ this.merkleRootTracker.pushRoot(blockNumber, currentRoot);
93
+ });
94
+ }
95
+ removeMembers(rlnInstance, toRemove) {
96
+ const removeDescending = new Map([...toRemove].reverse());
97
+ removeDescending.forEach((indexes, blockNumber) => {
98
+ indexes.forEach((index) => {
99
+ if (this._members.has(index)) {
100
+ this._members.delete(index);
101
+ rlnInstance.zerokit.deleteMember(index);
102
+ }
103
+ });
104
+ this.merkleRootTracker.backFill(blockNumber);
105
+ });
106
+ }
107
+ }
108
+
109
+ export { RLNContract };
@@ -1,3 +1,5 @@
1
+ import { hmac } from '../../../node_modules/@noble/hashes/esm/hmac.js';
2
+ import { sha256 } from '../../../node_modules/@noble/hashes/esm/sha2.js';
1
3
  import '../../../node_modules/multiformats/dist/src/bases/base10.js';
2
4
  import '../../../node_modules/multiformats/dist/src/bases/base16.js';
3
5
  import '../../../node_modules/multiformats/dist/src/bases/base2.js';
@@ -10,15 +12,18 @@ import '../../../node_modules/multiformats/dist/src/bases/base8.js';
10
12
  import '../../../node_modules/multiformats/dist/src/bases/identity.js';
11
13
  import '../../../node_modules/multiformats/dist/src/codecs/json.js';
12
14
  import { Logger } from '../../utils/dist/logger.js';
13
- import { RLN_CONTRACT } from './contract/constants.js';
15
+ import { RLN_CONTRACT, RLN_Q } from './contract/constants.js';
14
16
  import { RLNBaseContract } from './contract/rln_base_contract.js';
17
+ import { IdentityCredential } from './identity.js';
15
18
  import { Keystore } from './keystore/keystore.js';
19
+ import { BytesUtils } from './utils/bytes.js';
16
20
  import { extractMetaMaskSigner } from './utils/metamask.js';
17
21
  import './utils/epoch.js';
18
22
 
19
23
  const log = new Logger("waku:credentials");
20
24
  /**
21
25
  * Manages credentials for RLN
26
+ * This is a lightweight implementation of the RLN contract that doesn't require Zerokit
22
27
  * It is used to register membership and generate identity credentials
23
28
  */
24
29
  class RLNCredentialsManager {
@@ -59,7 +64,7 @@ class RLNCredentialsManager {
59
64
  this.contract = await RLNBaseContract.create({
60
65
  address: address,
61
66
  signer: signer,
62
- rateLimit: rateLimit ?? this.zerokit.rateLimit
67
+ rateLimit: rateLimit ?? this.zerokit?.rateLimit
63
68
  });
64
69
  log.info("RLNCredentialsManager successfully started");
65
70
  this.started = true;
@@ -80,8 +85,15 @@ class RLNCredentialsManager {
80
85
  log.info("Registering membership");
81
86
  let identity = "identity" in options && options.identity;
82
87
  if ("signature" in options) {
83
- log.info("Using Zerokit to generate identity");
84
- identity = this.zerokit.generateSeededIdentityCredential(options.signature);
88
+ log.info("Generating identity from signature");
89
+ if (this.zerokit) {
90
+ log.info("Using Zerokit to generate identity");
91
+ identity = this.zerokit.generateSeededIdentityCredential(options.signature);
92
+ }
93
+ else {
94
+ log.info("Using local implementation to generate identity");
95
+ identity = await this.generateSeededIdentityCredential(options.signature);
96
+ }
85
97
  }
86
98
  if (!identity) {
87
99
  log.error("Missing signature or identity to register membership");
@@ -170,6 +182,35 @@ class RLNCredentialsManager {
170
182
  throw Error(`Failed to verify chain coordinates: credentials chainID=${chainId} is not equal to registryContract chainID=${currentChainId}`);
171
183
  }
172
184
  }
185
+ /**
186
+ * Generates an identity credential from a seed string
187
+ * This is a pure implementation that doesn't rely on Zerokit
188
+ * @param seed A string seed to generate the identity from
189
+ * @returns IdentityCredential
190
+ */
191
+ async generateSeededIdentityCredential(seed) {
192
+ log.info("Generating seeded identity credential");
193
+ // Convert the seed to bytes
194
+ const encoder = new TextEncoder();
195
+ const seedBytes = encoder.encode(seed);
196
+ // Generate deterministic values using HMAC-SHA256
197
+ // We use different context strings for each component to ensure they're different
198
+ const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
199
+ const idNullifierBE = hmac(sha256, seedBytes, encoder.encode("IDNullifier"));
200
+ const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
201
+ const idSecretHashBE = sha256(combinedBytes);
202
+ const idCommitmentRawBE = sha256(idSecretHashBE);
203
+ const idCommitmentBE = this.reduceIdCommitment(idCommitmentRawBE);
204
+ log.info("Successfully generated identity credential, storing in Big Endian format");
205
+ return new IdentityCredential(idTrapdoorBE, idNullifierBE, idSecretHashBE, idCommitmentBE);
206
+ }
207
+ /**
208
+ * Helper: take 32-byte BE, reduce mod Q, return 32-byte BE
209
+ */
210
+ reduceIdCommitment(bytesBE, limit = RLN_Q) {
211
+ const nBE = BytesUtils.buildBigIntFromUint8ArrayBE(bytesBE);
212
+ return BytesUtils.bigIntToUint8Array32BE(nBE % limit);
213
+ }
173
214
  }
174
215
 
175
216
  export { RLNCredentialsManager };
@@ -14,7 +14,8 @@ class IdentityCredential {
14
14
  this.IDNullifier = IDNullifier;
15
15
  this.IDSecretHash = IDSecretHash;
16
16
  this.IDCommitment = IDCommitment;
17
- this.IDCommitmentBigInt = BytesUtils.toBigInt(IDCommitment);
17
+ this.IDCommitmentBigInt =
18
+ BytesUtils.buildBigIntFromUint8ArrayBE(IDCommitment);
18
19
  }
19
20
  static fromBytes(memKeys) {
20
21
  if (memKeys.length < 128) {
@@ -166,13 +166,18 @@ class Keystore {
166
166
  const idTrapdoorLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idTrapdoor", []));
167
167
  const idNullifierLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idNullifier", []));
168
168
  const idSecretHashLE = Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idSecretHash", []));
169
- const idCommitmentBigInt = BytesUtils.toBigInt(idCommitmentLE);
169
+ // Big Endian
170
+ const idCommitmentBE = BytesUtils.switchEndianness(idCommitmentLE);
171
+ const idTrapdoorBE = BytesUtils.switchEndianness(idTrapdoorLE);
172
+ const idNullifierBE = BytesUtils.switchEndianness(idNullifierLE);
173
+ const idSecretHashBE = BytesUtils.switchEndianness(idSecretHashLE);
174
+ const idCommitmentBigInt = BytesUtils.buildBigIntFromUint8ArrayBE(idCommitmentBE);
170
175
  return {
171
176
  identity: {
172
- IDCommitment: idCommitmentLE,
173
- IDTrapdoor: idTrapdoorLE,
174
- IDNullifier: idNullifierLE,
175
- IDSecretHash: idSecretHashLE,
177
+ IDCommitment: idCommitmentBE,
178
+ IDTrapdoor: idTrapdoorBE,
179
+ IDNullifier: idNullifierBE,
180
+ IDSecretHash: idSecretHashBE,
176
181
  IDCommitmentBigInt: idCommitmentBigInt
177
182
  },
178
183
  membership: {
@@ -209,15 +214,31 @@ class Keystore {
209
214
  }
210
215
  // follows nwaku implementation
211
216
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
217
+ // IdentityCredential is stored in Big Endian format => switch to Little Endian
212
218
  static fromIdentityToBytes(options) {
213
219
  const { IDCommitment, IDNullifier, IDSecretHash, IDTrapdoor } = options.identity;
220
+ const idCommitmentLE = BytesUtils.switchEndianness(IDCommitment);
221
+ const idNullifierLE = BytesUtils.switchEndianness(IDNullifier);
222
+ const idSecretHashLE = BytesUtils.switchEndianness(IDSecretHash);
223
+ const idTrapdoorLE = BytesUtils.switchEndianness(IDTrapdoor);
224
+ // eslint-disable-next-line no-console
225
+ console.log({
226
+ idCommitmentBE: IDCommitment,
227
+ idCommitmentLE,
228
+ idNullifierBE: IDNullifier,
229
+ idNullifierLE,
230
+ idSecretHashBE: IDSecretHash,
231
+ idSecretHashLE,
232
+ idTrapdoorBE: IDTrapdoor,
233
+ idTrapdoorLE
234
+ });
214
235
  return utf8ToBytes(JSON.stringify({
215
236
  treeIndex: options.membership.treeIndex,
216
237
  identityCredential: {
217
- idCommitment: Array.from(IDCommitment),
218
- idNullifier: Array.from(IDNullifier),
219
- idSecretHash: Array.from(IDSecretHash),
220
- idTrapdoor: Array.from(IDTrapdoor)
238
+ idCommitment: Array.from(idCommitmentLE),
239
+ idNullifier: Array.from(idNullifierLE),
240
+ idSecretHash: Array.from(idSecretHashLE),
241
+ idTrapdoor: Array.from(idTrapdoorLE)
221
242
  },
222
243
  membershipContract: {
223
244
  chainId: options.membership.chainId,
@@ -0,0 +1,59 @@
1
+ import { Version } from '../../core/dist/lib/message/version_0.js';
2
+ import '../../core/dist/lib/filter/filter.js';
3
+ import '../../core/dist/lib/light_push/light_push.js';
4
+ import '../../core/dist/lib/store/store.js';
5
+ import '../../core/dist/lib/connection_manager/connection_manager.js';
6
+ import { utf8ToBytes } from '../../utils/dist/bytes/index.js';
7
+ import '../../../node_modules/debug/src/browser.js';
8
+ import '../../core/dist/lib/metadata/metadata.js';
9
+ import { epochBytesToInt } from './utils/epoch.js';
10
+
11
+ function toRLNSignal(contentTopic, msg) {
12
+ const contentTopicBytes = utf8ToBytes(contentTopic ?? "");
13
+ return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
14
+ }
15
+ class RlnMessage {
16
+ rlnInstance;
17
+ msg;
18
+ rateLimitProof;
19
+ pubsubTopic = "";
20
+ version = Version;
21
+ constructor(rlnInstance, msg, rateLimitProof) {
22
+ this.rlnInstance = rlnInstance;
23
+ this.msg = msg;
24
+ this.rateLimitProof = rateLimitProof;
25
+ }
26
+ verify(roots) {
27
+ return this.rateLimitProof
28
+ ? this.rlnInstance.zerokit.verifyWithRoots(this.rateLimitProof, toRLNSignal(this.msg.contentTopic, this.msg), roots) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
29
+ : undefined;
30
+ }
31
+ verifyNoRoot() {
32
+ return this.rateLimitProof
33
+ ? this.rlnInstance.zerokit.verifyWithNoRoot(this.rateLimitProof, toRLNSignal(this.msg.contentTopic, this.msg)) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
34
+ : undefined;
35
+ }
36
+ get payload() {
37
+ return this.msg.payload;
38
+ }
39
+ get contentTopic() {
40
+ return this.msg.contentTopic;
41
+ }
42
+ get timestamp() {
43
+ return this.msg.timestamp;
44
+ }
45
+ get ephemeral() {
46
+ return this.msg.ephemeral;
47
+ }
48
+ get meta() {
49
+ return this.msg.meta;
50
+ }
51
+ get epoch() {
52
+ const bytes = this.rateLimitProof?.epoch;
53
+ if (!bytes)
54
+ return undefined;
55
+ return epochBytesToInt(bytes);
56
+ }
57
+ }
58
+
59
+ export { RlnMessage, toRLNSignal };
@@ -0,0 +1,54 @@
1
+ import { BytesUtils } from './utils/bytes.js';
2
+ import { poseidonHash } from './utils/hash.js';
3
+ import './utils/epoch.js';
4
+
5
+ const proofOffset = 128;
6
+ const rootOffset = proofOffset + 32;
7
+ const epochOffset = rootOffset + 32;
8
+ const shareXOffset = epochOffset + 32;
9
+ const shareYOffset = shareXOffset + 32;
10
+ const nullifierOffset = shareYOffset + 32;
11
+ const rlnIdentifierOffset = nullifierOffset + 32;
12
+ class ProofMetadata {
13
+ nullifier;
14
+ shareX;
15
+ shareY;
16
+ externalNullifier;
17
+ constructor(nullifier, shareX, shareY, externalNullifier) {
18
+ this.nullifier = nullifier;
19
+ this.shareX = shareX;
20
+ this.shareY = shareY;
21
+ this.externalNullifier = externalNullifier;
22
+ }
23
+ }
24
+ class Proof {
25
+ proof;
26
+ merkleRoot;
27
+ epoch;
28
+ shareX;
29
+ shareY;
30
+ nullifier;
31
+ rlnIdentifier;
32
+ constructor(proofBytes) {
33
+ if (proofBytes.length < rlnIdentifierOffset) {
34
+ throw new Error("invalid proof");
35
+ }
36
+ // parse the proof as proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32>
37
+ this.proof = proofBytes.subarray(0, proofOffset);
38
+ this.merkleRoot = proofBytes.subarray(proofOffset, rootOffset);
39
+ this.epoch = proofBytes.subarray(rootOffset, epochOffset);
40
+ this.shareX = proofBytes.subarray(epochOffset, shareXOffset);
41
+ this.shareY = proofBytes.subarray(shareXOffset, shareYOffset);
42
+ this.nullifier = proofBytes.subarray(shareYOffset, nullifierOffset);
43
+ this.rlnIdentifier = proofBytes.subarray(nullifierOffset, rlnIdentifierOffset);
44
+ }
45
+ extractMetadata() {
46
+ const externalNullifier = poseidonHash(this.epoch, this.rlnIdentifier);
47
+ return new ProofMetadata(this.nullifier, this.shareX, this.shareY, externalNullifier);
48
+ }
49
+ }
50
+ function proofToBytes(p) {
51
+ return BytesUtils.concatenate(p.proof, p.merkleRoot, p.epoch, p.shareX, p.shareY, p.nullifier, p.rlnIdentifier);
52
+ }
53
+
54
+ export { Proof, proofToBytes };