@waku/rln 0.1.5-053bb95.0 → 0.1.5-35b50c3.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 (61) hide show
  1. package/bundle/_virtual/utils.js +2 -2
  2. package/bundle/_virtual/utils2.js +2 -2
  3. package/bundle/index.js +2 -1
  4. package/bundle/packages/rln/dist/contract/constants.js +6 -2
  5. package/bundle/packages/rln/dist/contract/rln_base_contract.js +279 -144
  6. package/bundle/packages/rln/dist/contract/rln_contract.js +74 -89
  7. package/bundle/packages/rln/dist/credentials_manager.js +1 -1
  8. package/bundle/packages/rln/dist/identity.js +0 -8
  9. package/bundle/packages/rln/dist/keystore/keystore.js +28 -15
  10. package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
  11. package/bundle/packages/rln/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
  12. package/bundle/packages/rln/node_modules/@noble/hashes/_sha2.js +1 -1
  13. package/bundle/packages/rln/node_modules/@noble/hashes/hmac.js +1 -1
  14. package/bundle/packages/rln/node_modules/@noble/hashes/pbkdf2.js +1 -1
  15. package/bundle/packages/rln/node_modules/@noble/hashes/scrypt.js +1 -1
  16. package/bundle/packages/rln/node_modules/@noble/hashes/sha256.js +1 -1
  17. package/bundle/packages/rln/node_modules/@noble/hashes/sha512.js +1 -1
  18. package/bundle/packages/rln/node_modules/@noble/hashes/utils.js +1 -1
  19. package/dist/.tsbuildinfo +1 -1
  20. package/dist/contract/constants.d.ts +1 -1
  21. package/dist/contract/constants.js +1 -1
  22. package/dist/contract/constants.js.map +1 -1
  23. package/dist/contract/index.d.ts +1 -0
  24. package/dist/contract/index.js +1 -0
  25. package/dist/contract/index.js.map +1 -1
  26. package/dist/contract/rln_base_contract.d.ts +27 -25
  27. package/dist/contract/rln_base_contract.js +279 -144
  28. package/dist/contract/rln_base_contract.js.map +1 -1
  29. package/dist/contract/rln_contract.d.ts +4 -24
  30. package/dist/contract/rln_contract.js +74 -89
  31. package/dist/contract/rln_contract.js.map +1 -1
  32. package/dist/contract/types.d.ts +5 -0
  33. package/dist/contract/types.js.map +1 -1
  34. package/dist/credentials_manager.js +1 -1
  35. package/dist/credentials_manager.js.map +1 -1
  36. package/dist/identity.d.ts +0 -1
  37. package/dist/identity.js +0 -8
  38. package/dist/identity.js.map +1 -1
  39. package/dist/index.d.ts +2 -1
  40. package/dist/index.js +1 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/keystore/keystore.d.ts +1 -0
  43. package/dist/keystore/keystore.js +28 -15
  44. package/dist/keystore/keystore.js.map +1 -1
  45. package/dist/keystore/types.d.ts +2 -2
  46. package/package.json +1 -1
  47. package/src/contract/constants.ts +1 -1
  48. package/src/contract/index.ts +1 -0
  49. package/src/contract/rln_base_contract.ts +427 -216
  50. package/src/contract/rln_contract.ts +95 -120
  51. package/src/contract/types.ts +5 -0
  52. package/src/credentials_manager.ts +1 -1
  53. package/src/identity.ts +0 -9
  54. package/src/index.ts +3 -1
  55. package/src/keystore/keystore.ts +54 -29
  56. package/src/keystore/types.ts +2 -2
  57. package/bundle/packages/rln/dist/contract/errors.js +0 -62
  58. package/dist/contract/errors.d.ts +0 -30
  59. package/dist/contract/errors.js +0 -61
  60. package/dist/contract/errors.js.map +0 -1
  61. package/src/contract/errors.ts +0 -75
@@ -5,122 +5,107 @@ import { hexToBytes } from '../../../utils/dist/bytes/index.js';
5
5
  import { Logger } from '../../../utils/dist/logger/index.js';
6
6
  import { MerkleRootTracker } from '../root_tracker.js';
7
7
  import { zeroPadLE } from '../utils/bytes.js';
8
- import { ContractStateError } from './errors.js';
9
8
  import { RLNBaseContract } from './rln_base_contract.js';
9
+ import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
10
10
 
11
11
  const log = new Logger("waku:rln:contract");
12
12
  class RLNContract extends RLNBaseContract {
13
13
  instance;
14
14
  merkleRootTracker;
15
- lastSyncedBlock = 0;
16
15
  /**
17
16
  * Asynchronous initializer for RLNContract.
18
17
  * Allows injecting a mocked contract for testing purposes.
19
18
  */
20
19
  static async init(rlnInstance, options) {
21
20
  const rlnContract = new RLNContract(rlnInstance, options);
22
- await rlnContract.syncState();
23
21
  return rlnContract;
24
22
  }
25
- /**
26
- * Override base contract method to keep Merkle tree in sync
27
- * Registers a new membership with the given commitment and rate limit
28
- */
29
- async registerMembership(idCommitment, rateLimit = this.getRateLimit()) {
30
- await super.registerMembership(idCommitment, rateLimit);
31
- await this.syncState();
32
- }
33
- /**
34
- * Override base contract method to keep Merkle tree in sync
35
- * Erases an existing membership from the contract
36
- */
37
- async eraseMembership(idCommitment, eraseFromMembershipSet = true) {
38
- await super.eraseMembership(idCommitment, eraseFromMembershipSet);
39
- await this.syncState();
40
- }
41
- /**
42
- * Gets the current Merkle root
43
- * Returns the latest valid root or empty array if no roots exist
44
- */
45
- async getMerkleRoot() {
46
- await this.syncState();
47
- const roots = this.merkleRootTracker.roots();
48
- return roots.length > 0 ? roots[0] : new Uint8Array();
49
- }
50
23
  constructor(rlnInstance, options) {
51
24
  super(options);
52
25
  this.instance = rlnInstance;
53
26
  const initialRoot = rlnInstance.zerokit.getMerkleRoot();
54
27
  this.merkleRootTracker = new MerkleRootTracker(5, initialRoot);
55
28
  }
56
- /**
57
- * Syncs the local Merkle tree with the current contract state
58
- */
59
- async syncState() {
60
- try {
61
- const currentBlock = await this.provider.getBlockNumber();
62
- // If we're already synced, just get new members
63
- if (this.lastSyncedBlock > 0) {
64
- await this.syncNewMembers(this.lastSyncedBlock, currentBlock);
65
- this.lastSyncedBlock = currentBlock;
29
+ processEvents(events) {
30
+ const toRemoveTable = new Map();
31
+ const toInsertTable = new Map();
32
+ events.forEach((evt) => {
33
+ if (!evt.args) {
66
34
  return;
67
35
  }
68
- // First time sync - get all members
69
- const nextIndex = await this.contract.nextFreeIndex();
70
- const members = await this.getMembersInRange(0, nextIndex.toNumber());
71
- // Clear existing members by deleting them one by one
72
- // This effectively resets the tree without needing resetTree()
73
- for (let i = 0; i < nextIndex.toNumber(); i++) {
74
- try {
75
- this.instance.zerokit.deleteMember(i);
36
+ if (evt.event === "MembershipErased" ||
37
+ evt.event === "MembershipExpired") {
38
+ let index = evt.args.index;
39
+ if (!index) {
40
+ return;
76
41
  }
77
- catch (error) {
78
- // Ignore errors for non-existent members
79
- continue;
42
+ if (typeof index === "number" || typeof index === "string") {
43
+ index = BigNumber.from(index);
44
+ }
45
+ else {
46
+ log.error("Index is not a number or string", {
47
+ index,
48
+ event: evt
49
+ });
50
+ return;
51
+ }
52
+ const toRemoveVal = toRemoveTable.get(evt.blockNumber);
53
+ if (toRemoveVal != undefined) {
54
+ toRemoveVal.push(index.toNumber());
55
+ toRemoveTable.set(evt.blockNumber, toRemoveVal);
56
+ }
57
+ else {
58
+ toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
80
59
  }
81
60
  }
82
- // Insert all members
83
- for (const member of members) {
84
- const idCommitment = zeroPadLE(hexToBytes(member.idCommitment), 32);
85
- this.instance.zerokit.insertMember(idCommitment);
61
+ else if (evt.event === "MembershipRegistered") {
62
+ let eventsPerBlock = toInsertTable.get(evt.blockNumber);
63
+ if (eventsPerBlock == undefined) {
64
+ eventsPerBlock = [];
65
+ }
66
+ eventsPerBlock.push(evt);
67
+ toInsertTable.set(evt.blockNumber, eventsPerBlock);
86
68
  }
87
- // Update root tracker
88
- const currentRoot = this.instance.zerokit.getMerkleRoot();
89
- this.merkleRootTracker.pushRoot(currentBlock, currentRoot);
90
- this.lastSyncedBlock = currentBlock;
91
- log.info(`Synced ${members.length} members to current block ${currentBlock}`);
92
- }
93
- catch (error) {
94
- log.error("Failed to sync state", error);
95
- throw new ContractStateError("Failed to sync contract state");
96
- }
69
+ });
70
+ this.removeMembers(this.instance, toRemoveTable);
71
+ this.insertMembers(this.instance, toInsertTable);
97
72
  }
98
- /**
99
- * Syncs new members added between fromBlock and toBlock
100
- */
101
- async syncNewMembers(fromBlock, toBlock) {
102
- // Get members that were added
103
- const filter = this.contract.filters.MembershipRegistered();
104
- const addEvents = await this.contract.queryFilter(filter, fromBlock, toBlock);
105
- // Get members that were removed
106
- const removeFilter = this.contract.filters.MembershipErased();
107
- const removeEvents = await this.contract.queryFilter(removeFilter, fromBlock, toBlock);
108
- // Process removals first (in reverse block order)
109
- for (const evt of removeEvents.sort((a, b) => b.blockNumber - a.blockNumber)) {
110
- if (!evt.args)
111
- continue;
112
- const index = evt.args.index.toNumber();
113
- this.instance.zerokit.deleteMember(index);
114
- this.merkleRootTracker.backFill(evt.blockNumber);
115
- }
116
- // Then process additions
117
- for (const evt of addEvents) {
118
- if (!evt.args)
119
- continue;
120
- const idCommitment = zeroPadLE(hexToBytes(evt.args.idCommitment), 32);
121
- this.instance.zerokit.insertMember(idCommitment);
122
- this.merkleRootTracker.pushRoot(evt.blockNumber, this.instance.zerokit.getMerkleRoot());
123
- }
73
+ insertMembers(rlnInstance, toInsert) {
74
+ toInsert.forEach((events, blockNumber) => {
75
+ events.forEach((evt) => {
76
+ if (!evt.args)
77
+ return;
78
+ const _idCommitment = evt.args.idCommitment;
79
+ let index = evt.args.index;
80
+ if (!_idCommitment || !index) {
81
+ return;
82
+ }
83
+ if (typeof index === "number" || typeof index === "string") {
84
+ index = BigNumber.from(index);
85
+ }
86
+ const idCommitment = zeroPadLE(hexToBytes(_idCommitment), 32);
87
+ rlnInstance.zerokit.insertMember(idCommitment);
88
+ const numericIndex = index.toNumber();
89
+ this._members.set(numericIndex, {
90
+ index,
91
+ idCommitment: _idCommitment
92
+ });
93
+ });
94
+ const currentRoot = rlnInstance.zerokit.getMerkleRoot();
95
+ this.merkleRootTracker.pushRoot(blockNumber, currentRoot);
96
+ });
97
+ }
98
+ removeMembers(rlnInstance, toRemove) {
99
+ const removeDescending = new Map([...toRemove].reverse());
100
+ removeDescending.forEach((indexes, blockNumber) => {
101
+ indexes.forEach((index) => {
102
+ if (this._members.has(index)) {
103
+ this._members.delete(index);
104
+ rlnInstance.zerokit.deleteMember(index);
105
+ }
106
+ });
107
+ this.merkleRootTracker.backFill(blockNumber);
108
+ });
124
109
  }
125
110
  }
126
111
 
@@ -126,7 +126,7 @@ class RLNCredentialsManager {
126
126
  options.address ||
127
127
  LINEA_CONTRACT.address;
128
128
  if (address === LINEA_CONTRACT.address) {
129
- chainId = LINEA_CONTRACT.chainId;
129
+ chainId = LINEA_CONTRACT.chainId.toString();
130
130
  log.info(`Using Linea contract with chainId: ${chainId}`);
131
131
  }
132
132
  const signer = options.signer || (await extractMetaMaskSigner());
@@ -25,14 +25,6 @@ class IdentityCredential {
25
25
  const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment, 32);
26
26
  return new IdentityCredential(idTrapdoor, idNullifier, idSecretHash, idCommitment, idCommitmentBigInt);
27
27
  }
28
- toJSON() {
29
- return {
30
- idTrapdoor: Array.from(this.IDTrapdoor),
31
- idNullifier: Array.from(this.IDNullifier),
32
- idSecretHash: Array.from(this.IDSecretHash),
33
- idCommitment: Array.from(this.IDCommitment)
34
- };
35
- }
36
28
  }
37
29
 
38
30
  export { IdentityCredential };
@@ -17,7 +17,6 @@ import { Logger } from '../../../utils/dist/logger/index.js';
17
17
  import { sha256 } from '../../../../node_modules/ethereum-cryptography/esm/sha256.js';
18
18
  import { bytesToUtf8 } from '../../../../node_modules/ethereum-cryptography/esm/utils.js';
19
19
  import _ from '../../../../node_modules/lodash/lodash.js';
20
- import { IdentityCredential } from '../identity.js';
21
20
  import { buildBigIntFromUint8Array } from '../utils/bytes.js';
22
21
  import { keccak256Checksum, decryptEipKeystore } from './cipher.js';
23
22
  import { isKeystoreValid, isCredentialValid } from './schema_validator.js';
@@ -165,15 +164,15 @@ class Keystore {
165
164
  try {
166
165
  const str = bytesToUtf8(bytes);
167
166
  const obj = JSON.parse(str);
168
- // Get identity fields from named object
169
- const { idTrapdoor, idNullifier, idSecretHash, idCommitment } = _.get(obj, "identityCredential", {});
170
- const idTrapdoorArray = new Uint8Array(idTrapdoor || []);
171
- const idNullifierArray = new Uint8Array(idNullifier || []);
172
- const idSecretHashArray = new Uint8Array(idSecretHash || []);
173
- const idCommitmentArray = new Uint8Array(idCommitment || []);
174
- const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitmentArray);
167
+ // TODO: add runtime validation of nwaku credentials
175
168
  return {
176
- identity: new IdentityCredential(idTrapdoorArray, idNullifierArray, idSecretHashArray, idCommitmentArray, idCommitmentBigInt),
169
+ identity: {
170
+ IDCommitment: Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idCommitment", [])),
171
+ IDTrapdoor: Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idTrapdoor", [])),
172
+ IDNullifier: Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idNullifier", [])),
173
+ IDCommitmentBigInt: buildBigIntFromUint8Array(Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idCommitment", []))),
174
+ IDSecretHash: Keystore.fromArraylikeToBytes(_.get(obj, "identityCredential.idSecretHash", []))
175
+ },
177
176
  membership: {
178
177
  treeIndex: _.get(obj, "treeIndex"),
179
178
  chainId: _.get(obj, "membershipContract.chainId"),
@@ -187,6 +186,20 @@ class Keystore {
187
186
  return;
188
187
  }
189
188
  }
189
+ static fromArraylikeToBytes(obj) {
190
+ if (Array.isArray(obj)) {
191
+ return new Uint8Array(obj);
192
+ }
193
+ const bytes = [];
194
+ let index = 0;
195
+ let lastElement = obj[index];
196
+ while (lastElement !== undefined) {
197
+ bytes.push(lastElement);
198
+ index += 1;
199
+ lastElement = obj[index];
200
+ }
201
+ return new Uint8Array(bytes);
202
+ }
190
203
  // follows nwaku implementation
191
204
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L111
192
205
  static computeMembershipHash(info) {
@@ -196,16 +209,16 @@ class Keystore {
196
209
  // https://github.com/waku-org/nwaku/blob/f05528d4be3d3c876a8b07f9bb7dfaae8aa8ec6e/waku/waku_keystore/protocol_types.nim#L98
197
210
  static fromIdentityToBytes(options) {
198
211
  return utf8ToBytes(JSON.stringify({
199
- membershipContract: {
200
- chainId: options.membership.chainId,
201
- address: options.membership.address
202
- },
203
212
  treeIndex: options.membership.treeIndex,
204
213
  identityCredential: {
205
- idTrapdoor: Array.from(options.identity.IDTrapdoor),
214
+ idCommitment: Array.from(options.identity.IDCommitment),
206
215
  idNullifier: Array.from(options.identity.IDNullifier),
207
216
  idSecretHash: Array.from(options.identity.IDSecretHash),
208
- idCommitment: Array.from(options.identity.IDCommitment)
217
+ idTrapdoor: Array.from(options.identity.IDTrapdoor)
218
+ },
219
+ membershipContract: {
220
+ chainId: options.membership.chainId,
221
+ address: options.membership.address
209
222
  },
210
223
  userMessageLimit: options.membership.rateLimit
211
224
  }));
@@ -1,6 +1,6 @@
1
1
  import { __exports as random } from '../../../../../../../_virtual/random.js';
2
2
  import '../../../../@noble/hashes/utils.js';
3
- import { __exports as utils } from '../../../../../../../_virtual/utils2.js';
3
+ import { __exports as utils } from '../../../../../../../_virtual/utils.js';
4
4
 
5
5
  Object.defineProperty(random, "__esModule", { value: true });
6
6
  random.getRandomBytes = random.getRandomBytesSync = void 0;
@@ -1,10 +1,10 @@
1
1
  import { commonjsGlobal } from '../../../../../../../_virtual/_commonjsHelpers.js';
2
2
  import { commonjsRequire } from '../../../../../../../_virtual/_commonjs-dynamic-modules.js';
3
- import { __module as utils } from '../../../../../../../_virtual/utils.js';
3
+ import { __module as utils } from '../../../../../../../_virtual/utils2.js';
4
4
  import '../../../../@noble/hashes/_assert.js';
5
5
  import '../../../../@noble/hashes/utils.js';
6
6
  import { __exports as _assert } from '../../../../../../../_virtual/_assert.js';
7
- import { __exports as utils$1 } from '../../../../../../../_virtual/utils2.js';
7
+ import { __exports as utils$1 } from '../../../../../../../_virtual/utils.js';
8
8
 
9
9
  utils.exports;
10
10
 
@@ -1,7 +1,7 @@
1
1
  import { __exports as _sha2 } from '../../../../../_virtual/_sha2.js';
2
2
  import './_assert.js';
3
3
  import './utils.js';
4
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
4
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
5
5
  import { __exports as _assert } from '../../../../../_virtual/_assert.js';
6
6
 
7
7
  Object.defineProperty(_sha2, "__esModule", { value: true });
@@ -1,7 +1,7 @@
1
1
  import { __exports as hmac } from '../../../../../_virtual/hmac.js';
2
2
  import './_assert.js';
3
3
  import './utils.js';
4
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
4
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
5
5
  import { __exports as _assert } from '../../../../../_virtual/_assert.js';
6
6
 
7
7
  (function (exports) {
@@ -2,7 +2,7 @@ import { __exports as pbkdf2$1 } from '../../../../../_virtual/pbkdf22.js';
2
2
  import './_assert.js';
3
3
  import './hmac.js';
4
4
  import './utils.js';
5
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
5
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
6
6
  import { __exports as _assert } from '../../../../../_virtual/_assert.js';
7
7
  import { __exports as hmac } from '../../../../../_virtual/hmac.js';
8
8
 
@@ -3,7 +3,7 @@ import './_assert.js';
3
3
  import './sha256.js';
4
4
  import './pbkdf2.js';
5
5
  import './utils.js';
6
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
6
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
7
7
  import { __exports as _assert } from '../../../../../_virtual/_assert.js';
8
8
  import { __exports as pbkdf2 } from '../../../../../_virtual/pbkdf22.js';
9
9
  import { __exports as sha256 } from '../../../../../_virtual/sha2562.js';
@@ -2,7 +2,7 @@ import { __exports as sha256 } from '../../../../../_virtual/sha2562.js';
2
2
  import './_sha2.js';
3
3
  import './utils.js';
4
4
  import { __exports as _sha2 } from '../../../../../_virtual/_sha2.js';
5
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
5
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
6
6
 
7
7
  Object.defineProperty(sha256, "__esModule", { value: true });
8
8
  sha256.sha224 = sha256.sha256 = void 0;
@@ -4,7 +4,7 @@ import './_u64.js';
4
4
  import './utils.js';
5
5
  import { __exports as _u64 } from '../../../../../_virtual/_u64.js';
6
6
  import { __exports as _sha2 } from '../../../../../_virtual/_sha2.js';
7
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
7
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
8
8
 
9
9
  Object.defineProperty(sha512, "__esModule", { value: true });
10
10
  sha512.sha384 = sha512.sha512_256 = sha512.sha512_224 = sha512.sha512 = sha512.SHA512 = void 0;
@@ -1,4 +1,4 @@
1
- import { __exports as utils } from '../../../../../_virtual/utils2.js';
1
+ import { __exports as utils } from '../../../../../_virtual/utils.js';
2
2
  import './cryptoBrowser.js';
3
3
  import { __exports as cryptoBrowser } from '../../../../../_virtual/cryptoBrowser.js';
4
4