@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,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, RLN_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: RLN_CONTRACT.address }),
40
+ MembershipErased: () => ({ address: RLN_CONTRACT.address }),
41
+ MembershipExpired: () => ({ address: RLN_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: RLN_CONTRACT.address }),
55
+ MembershipErased: () => ({ address: RLN_CONTRACT.address }),
56
+ MembershipExpired: () => ({ address: RLN_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: RLN_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: RLN_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,8 +1,11 @@
1
+ import { hmac } from "@noble/hashes/hmac";
2
+ import { sha256 } from "@noble/hashes/sha2";
1
3
  import { Logger } from "@waku/utils";
2
4
  import { ethers } from "ethers";
3
5
 
4
- import { RLN_CONTRACT } from "./contract/constants.js";
6
+ import { RLN_CONTRACT, RLN_Q } from "./contract/constants.js";
5
7
  import { RLNBaseContract } from "./contract/rln_base_contract.js";
8
+ import { IdentityCredential } from "./identity.js";
6
9
  import { Keystore } from "./keystore/index.js";
7
10
  import type {
8
11
  DecryptedCredentials,
@@ -10,6 +13,7 @@ import type {
10
13
  } from "./keystore/index.js";
11
14
  import { KeystoreEntity, Password } from "./keystore/types.js";
12
15
  import { RegisterMembershipOptions, StartRLNOptions } from "./types.js";
16
+ import { BytesUtils } from "./utils/bytes.js";
13
17
  import { extractMetaMaskSigner } from "./utils/index.js";
14
18
  import { Zerokit } from "./zerokit.js";
15
19
 
@@ -17,6 +21,7 @@ const log = new Logger("waku:credentials");
17
21
 
18
22
  /**
19
23
  * Manages credentials for RLN
24
+ * This is a lightweight implementation of the RLN contract that doesn't require Zerokit
20
25
  * It is used to register membership and generate identity credentials
21
26
  */
22
27
  export class RLNCredentialsManager {
@@ -29,9 +34,9 @@ export class RLNCredentialsManager {
29
34
  protected keystore = Keystore.create();
30
35
  public credentials: undefined | DecryptedCredentials;
31
36
 
32
- public zerokit: Zerokit;
37
+ public zerokit: undefined | Zerokit;
33
38
 
34
- public constructor(zerokit: Zerokit) {
39
+ public constructor(zerokit?: Zerokit) {
35
40
  log.info("RLNCredentialsManager initialized");
36
41
  this.zerokit = zerokit;
37
42
  }
@@ -76,7 +81,7 @@ export class RLNCredentialsManager {
76
81
  this.contract = await RLNBaseContract.create({
77
82
  address: address!,
78
83
  signer: signer!,
79
- rateLimit: rateLimit ?? this.zerokit.rateLimit
84
+ rateLimit: rateLimit ?? this.zerokit?.rateLimit
80
85
  });
81
86
 
82
87
  log.info("RLNCredentialsManager successfully started");
@@ -101,10 +106,18 @@ export class RLNCredentialsManager {
101
106
  let identity = "identity" in options && options.identity;
102
107
 
103
108
  if ("signature" in options) {
104
- log.info("Using Zerokit to generate identity");
105
- identity = this.zerokit.generateSeededIdentityCredential(
106
- options.signature
107
- );
109
+ log.info("Generating identity from signature");
110
+ if (this.zerokit) {
111
+ log.info("Using Zerokit to generate identity");
112
+ identity = this.zerokit.generateSeededIdentityCredential(
113
+ options.signature
114
+ );
115
+ } else {
116
+ log.info("Using local implementation to generate identity");
117
+ identity = await this.generateSeededIdentityCredential(
118
+ options.signature
119
+ );
120
+ }
108
121
  }
109
122
 
110
123
  if (!identity) {
@@ -229,4 +242,55 @@ export class RLNCredentialsManager {
229
242
  );
230
243
  }
231
244
  }
245
+
246
+ /**
247
+ * Generates an identity credential from a seed string
248
+ * This is a pure implementation that doesn't rely on Zerokit
249
+ * @param seed A string seed to generate the identity from
250
+ * @returns IdentityCredential
251
+ */
252
+ private async generateSeededIdentityCredential(
253
+ seed: string
254
+ ): Promise<IdentityCredential> {
255
+ log.info("Generating seeded identity credential");
256
+ // Convert the seed to bytes
257
+ const encoder = new TextEncoder();
258
+ const seedBytes = encoder.encode(seed);
259
+
260
+ // Generate deterministic values using HMAC-SHA256
261
+ // We use different context strings for each component to ensure they're different
262
+ const idTrapdoorBE = hmac(sha256, seedBytes, encoder.encode("IDTrapdoor"));
263
+ const idNullifierBE = hmac(
264
+ sha256,
265
+ seedBytes,
266
+ encoder.encode("IDNullifier")
267
+ );
268
+
269
+ const combinedBytes = new Uint8Array([...idTrapdoorBE, ...idNullifierBE]);
270
+ const idSecretHashBE = sha256(combinedBytes);
271
+
272
+ const idCommitmentRawBE = sha256(idSecretHashBE);
273
+ const idCommitmentBE = this.reduceIdCommitment(idCommitmentRawBE);
274
+
275
+ log.info(
276
+ "Successfully generated identity credential, storing in Big Endian format"
277
+ );
278
+ return new IdentityCredential(
279
+ idTrapdoorBE,
280
+ idNullifierBE,
281
+ idSecretHashBE,
282
+ idCommitmentBE
283
+ );
284
+ }
285
+
286
+ /**
287
+ * Helper: take 32-byte BE, reduce mod Q, return 32-byte BE
288
+ */
289
+ private reduceIdCommitment(
290
+ bytesBE: Uint8Array,
291
+ limit: bigint = RLN_Q
292
+ ): Uint8Array {
293
+ const nBE = BytesUtils.buildBigIntFromUint8ArrayBE(bytesBE);
294
+ return BytesUtils.bigIntToUint8Array32BE(nBE % limit);
295
+ }
232
296
  }
package/src/identity.ts CHANGED
@@ -11,7 +11,8 @@ export class IdentityCredential {
11
11
  public readonly IDSecretHash: Uint8Array,
12
12
  public readonly IDCommitment: Uint8Array
13
13
  ) {
14
- this.IDCommitmentBigInt = BytesUtils.toBigInt(IDCommitment);
14
+ this.IDCommitmentBigInt =
15
+ BytesUtils.buildBigIntFromUint8ArrayBE(IDCommitment);
15
16
  }
16
17
 
17
18
  public static fromBytes(memKeys: Uint8Array): IdentityCredential {
package/src/index.ts CHANGED
@@ -1,18 +1,28 @@
1
+ import { RLNDecoder, RLNEncoder } from "./codec.js";
1
2
  import { RLN_ABI } from "./contract/abi/rln.js";
2
- import { RLN_CONTRACT } from "./contract/index.js";
3
+ import { RLN_CONTRACT, RLNContract } from "./contract/index.js";
3
4
  import { RLNBaseContract } from "./contract/rln_base_contract.js";
4
5
  import { createRLN } from "./create.js";
6
+ import { RLNCredentialsManager } from "./credentials_manager.js";
5
7
  import { IdentityCredential } from "./identity.js";
6
8
  import { Keystore } from "./keystore/index.js";
9
+ import { Proof } from "./proof.js";
7
10
  import { RLNInstance } from "./rln.js";
11
+ import { MerkleRootTracker } from "./root_tracker.js";
8
12
  import { extractMetaMaskSigner } from "./utils/index.js";
9
13
 
10
14
  export {
15
+ RLNCredentialsManager,
11
16
  RLNBaseContract,
12
17
  createRLN,
13
18
  Keystore,
14
19
  RLNInstance,
15
20
  IdentityCredential,
21
+ Proof,
22
+ RLNEncoder,
23
+ RLNDecoder,
24
+ MerkleRootTracker,
25
+ RLNContract,
16
26
  RLN_CONTRACT,
17
27
  extractMetaMaskSigner,
18
28
  RLN_ABI
@@ -264,14 +264,20 @@ export class Keystore {
264
264
  _.get(obj, "identityCredential.idSecretHash", [])
265
265
  );
266
266
 
267
- const idCommitmentBigInt = BytesUtils.toBigInt(idCommitmentLE);
267
+ // Big Endian
268
+ const idCommitmentBE = BytesUtils.switchEndianness(idCommitmentLE);
269
+ const idTrapdoorBE = BytesUtils.switchEndianness(idTrapdoorLE);
270
+ const idNullifierBE = BytesUtils.switchEndianness(idNullifierLE);
271
+ const idSecretHashBE = BytesUtils.switchEndianness(idSecretHashLE);
272
+ const idCommitmentBigInt =
273
+ BytesUtils.buildBigIntFromUint8ArrayBE(idCommitmentBE);
268
274
 
269
275
  return {
270
276
  identity: {
271
- IDCommitment: idCommitmentLE,
272
- IDTrapdoor: idTrapdoorLE,
273
- IDNullifier: idNullifierLE,
274
- IDSecretHash: idSecretHashLE,
277
+ IDCommitment: idCommitmentBE,
278
+ IDTrapdoor: idTrapdoorBE,
279
+ IDNullifier: idNullifierBE,
280
+ IDSecretHash: idSecretHashBE,
275
281
  IDCommitmentBigInt: idCommitmentBigInt
276
282
  },
277
283
  membership: {
@@ -323,18 +329,35 @@ export class Keystore {
323
329
 
324
330
  // follows nwaku implementation
325
331
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
332
+ // IdentityCredential is stored in Big Endian format => switch to Little Endian
326
333
  private static fromIdentityToBytes(options: KeystoreEntity): Uint8Array {
327
334
  const { IDCommitment, IDNullifier, IDSecretHash, IDTrapdoor } =
328
335
  options.identity;
336
+ const idCommitmentLE = BytesUtils.switchEndianness(IDCommitment);
337
+ const idNullifierLE = BytesUtils.switchEndianness(IDNullifier);
338
+ const idSecretHashLE = BytesUtils.switchEndianness(IDSecretHash);
339
+ const idTrapdoorLE = BytesUtils.switchEndianness(IDTrapdoor);
340
+
341
+ // eslint-disable-next-line no-console
342
+ console.log({
343
+ idCommitmentBE: IDCommitment,
344
+ idCommitmentLE,
345
+ idNullifierBE: IDNullifier,
346
+ idNullifierLE,
347
+ idSecretHashBE: IDSecretHash,
348
+ idSecretHashLE,
349
+ idTrapdoorBE: IDTrapdoor,
350
+ idTrapdoorLE
351
+ });
329
352
 
330
353
  return utf8ToBytes(
331
354
  JSON.stringify({
332
355
  treeIndex: options.membership.treeIndex,
333
356
  identityCredential: {
334
- idCommitment: Array.from(IDCommitment),
335
- idNullifier: Array.from(IDNullifier),
336
- idSecretHash: Array.from(IDSecretHash),
337
- idTrapdoor: Array.from(IDTrapdoor)
357
+ idCommitment: Array.from(idCommitmentLE),
358
+ idNullifier: Array.from(idNullifierLE),
359
+ idSecretHash: Array.from(idSecretHashLE),
360
+ idTrapdoor: Array.from(idTrapdoorLE)
338
361
  },
339
362
  membershipContract: {
340
363
  chainId: options.membership.chainId,
package/src/message.ts ADDED
@@ -0,0 +1,73 @@
1
+ import { message } from "@waku/core";
2
+ import type {
3
+ IDecodedMessage,
4
+ IMessage,
5
+ IRateLimitProof,
6
+ IRlnMessage
7
+ } from "@waku/interfaces";
8
+ import * as utils from "@waku/utils/bytes";
9
+
10
+ import { RLNInstance } from "./rln.js";
11
+ import { epochBytesToInt } from "./utils/index.js";
12
+
13
+ export function toRLNSignal(contentTopic: string, msg: IMessage): Uint8Array {
14
+ const contentTopicBytes = utils.utf8ToBytes(contentTopic ?? "");
15
+ return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
16
+ }
17
+
18
+ export class RlnMessage<T extends IDecodedMessage> implements IRlnMessage {
19
+ public pubsubTopic = "";
20
+ public version = message.version_0.Version;
21
+
22
+ public constructor(
23
+ private rlnInstance: RLNInstance,
24
+ private msg: T,
25
+ public rateLimitProof: IRateLimitProof | undefined
26
+ ) {}
27
+
28
+ public verify(roots: Uint8Array[]): boolean | undefined {
29
+ return this.rateLimitProof
30
+ ? this.rlnInstance.zerokit.verifyWithRoots(
31
+ this.rateLimitProof,
32
+ toRLNSignal(this.msg.contentTopic, this.msg),
33
+ roots
34
+ ) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
35
+ : undefined;
36
+ }
37
+
38
+ public verifyNoRoot(): boolean | undefined {
39
+ return this.rateLimitProof
40
+ ? this.rlnInstance.zerokit.verifyWithNoRoot(
41
+ this.rateLimitProof,
42
+ toRLNSignal(this.msg.contentTopic, this.msg)
43
+ ) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
44
+ : undefined;
45
+ }
46
+
47
+ public get payload(): Uint8Array {
48
+ return this.msg.payload;
49
+ }
50
+
51
+ public get contentTopic(): string {
52
+ return this.msg.contentTopic;
53
+ }
54
+
55
+ public get timestamp(): Date | undefined {
56
+ return this.msg.timestamp;
57
+ }
58
+
59
+ public get ephemeral(): boolean | undefined {
60
+ return this.msg.ephemeral;
61
+ }
62
+
63
+ public get meta(): Uint8Array | undefined {
64
+ return this.msg.meta;
65
+ }
66
+
67
+ public get epoch(): number | undefined {
68
+ const bytes = this.rateLimitProof?.epoch;
69
+ if (!bytes) return undefined;
70
+
71
+ return epochBytesToInt(bytes);
72
+ }
73
+ }
package/src/proof.ts ADDED
@@ -0,0 +1,69 @@
1
+ import type { IRateLimitProof } from "@waku/interfaces";
2
+
3
+ import { BytesUtils, poseidonHash } from "./utils/index.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
+
13
+ class ProofMetadata {
14
+ public constructor(
15
+ public readonly nullifier: Uint8Array,
16
+ public readonly shareX: Uint8Array,
17
+ public readonly shareY: Uint8Array,
18
+ public readonly externalNullifier: Uint8Array
19
+ ) {}
20
+ }
21
+
22
+ export class Proof implements IRateLimitProof {
23
+ public readonly proof: Uint8Array;
24
+ public readonly merkleRoot: Uint8Array;
25
+ public readonly epoch: Uint8Array;
26
+ public readonly shareX: Uint8Array;
27
+ public readonly shareY: Uint8Array;
28
+ public readonly nullifier: Uint8Array;
29
+ public readonly rlnIdentifier: Uint8Array;
30
+
31
+ public constructor(proofBytes: Uint8Array) {
32
+ if (proofBytes.length < rlnIdentifierOffset) {
33
+ throw new Error("invalid proof");
34
+ }
35
+ // parse the proof as proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32>
36
+ this.proof = proofBytes.subarray(0, proofOffset);
37
+ this.merkleRoot = proofBytes.subarray(proofOffset, rootOffset);
38
+ this.epoch = proofBytes.subarray(rootOffset, epochOffset);
39
+ this.shareX = proofBytes.subarray(epochOffset, shareXOffset);
40
+ this.shareY = proofBytes.subarray(shareXOffset, shareYOffset);
41
+ this.nullifier = proofBytes.subarray(shareYOffset, nullifierOffset);
42
+ this.rlnIdentifier = proofBytes.subarray(
43
+ nullifierOffset,
44
+ rlnIdentifierOffset
45
+ );
46
+ }
47
+
48
+ public extractMetadata(): ProofMetadata {
49
+ const externalNullifier = poseidonHash(this.epoch, this.rlnIdentifier);
50
+ return new ProofMetadata(
51
+ this.nullifier,
52
+ this.shareX,
53
+ this.shareY,
54
+ externalNullifier
55
+ );
56
+ }
57
+ }
58
+
59
+ export function proofToBytes(p: IRateLimitProof): Uint8Array {
60
+ return BytesUtils.concatenate(
61
+ p.proof,
62
+ p.merkleRoot,
63
+ p.epoch,
64
+ p.shareX,
65
+ p.shareY,
66
+ p.nullifier,
67
+ p.rlnIdentifier
68
+ );
69
+ }
@@ -0,0 +1,13 @@
1
+ declare const verificationKey: {
2
+ protocol: string;
3
+ curve: string;
4
+ nPublic: number;
5
+ vk_alpha_1: string[];
6
+ vk_beta_2: string[][];
7
+ vk_gamma_2: string[][];
8
+ vk_delta_2: string[][];
9
+ vk_alphabeta_12: string[][][];
10
+ IC: string[][];
11
+ };
12
+
13
+ export default verificationKey;
@@ -1,25 +1,11 @@
1
- export const builder: (
1
+ export async function builder(
2
2
  code: Uint8Array,
3
- sanityCheck?: boolean
4
- ) => Promise<WitnessCalculator>;
3
+ sanityCheck: boolean
4
+ ): Promise<WitnessCalculator>;
5
5
 
6
6
  export class WitnessCalculator {
7
- constructor(instance: any, sanityCheck?: boolean);
8
-
9
- circom_version(): number;
10
-
11
- calculateWitness(
12
- input: Record<string, unknown>,
13
- sanityCheck?: boolean
14
- ): Promise<bigint[]>;
15
-
16
- calculateBinWitness(
17
- input: Record<string, unknown>,
18
- sanityCheck?: boolean
19
- ): Promise<Uint8Array>;
20
-
21
- calculateWTNSBin(
22
- input: Record<string, unknown>,
23
- sanityCheck?: boolean
24
- ): Promise<Uint8Array>;
7
+ public calculateWitness(
8
+ input: unknown,
9
+ sanityCheck: boolean
10
+ ): Promise<Array<bigint>>;
25
11
  }