@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.
- package/bundle/_virtual/utils.js +2 -2
- package/bundle/_virtual/utils2.js +2 -2
- package/bundle/index.js +6 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/_sha2.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/hmac.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/pbkdf2.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/scrypt.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/sha256.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/sha512.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/@noble/hashes/utils.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +1 -1
- package/bundle/node_modules/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +2 -2
- package/bundle/node_modules/@chainsafe/is-ip/lib/is-ip.js +12 -0
- package/bundle/node_modules/@chainsafe/is-ip/lib/parse.js +26 -0
- package/bundle/node_modules/@chainsafe/is-ip/lib/parser.js +202 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/constants.js +43 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/errors.js +17 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/registry.js +245 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/utils.js +191 -0
- package/bundle/node_modules/@multiformats/multiaddr/dist/src/validation.js +30 -0
- package/bundle/node_modules/@noble/hashes/esm/hmac.js +88 -0
- package/bundle/node_modules/@noble/hashes/esm/sha3.js +1 -1
- package/bundle/node_modules/@noble/hashes/esm/utils.js +8 -1
- package/bundle/node_modules/@waku/zerokit-rln-wasm/rln_wasm.js +517 -255
- package/bundle/node_modules/it-length-prefixed/dist/src/decode.js +6 -0
- package/bundle/node_modules/multiformats/dist/src/bases/base10.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/base16.js +4 -2
- package/bundle/node_modules/multiformats/dist/src/bases/base2.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/base256emoji.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/base32.js +11 -9
- package/bundle/node_modules/multiformats/dist/src/bases/base36.js +4 -2
- package/bundle/node_modules/multiformats/dist/src/bases/base58.js +4 -2
- package/bundle/node_modules/multiformats/dist/src/bases/base64.js +6 -4
- package/bundle/node_modules/multiformats/dist/src/bases/base8.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/bases/identity.js +3 -1
- package/bundle/node_modules/multiformats/dist/src/basics.js +15 -0
- package/bundle/node_modules/multiformats/dist/src/bytes.js +15 -1
- package/bundle/node_modules/multiformats/dist/src/cid.js +371 -0
- package/bundle/node_modules/multiformats/dist/src/hashes/digest.js +62 -0
- package/bundle/node_modules/multiformats/dist/src/varint.js +15 -0
- package/bundle/node_modules/multiformats/dist/src/vendor/varint.js +78 -0
- package/bundle/node_modules/protons-runtime/dist/src/codec.js +20 -0
- package/bundle/node_modules/protons-runtime/dist/src/codecs/enum.js +24 -0
- package/bundle/node_modules/protons-runtime/dist/src/codecs/message.js +7 -0
- package/bundle/node_modules/protons-runtime/dist/src/decode.js +8 -0
- package/bundle/node_modules/protons-runtime/dist/src/encode.js +11 -0
- package/bundle/node_modules/protons-runtime/dist/src/index.js +30 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/float.js +54 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/longbits.js +175 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/pool.js +28 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/reader.js +367 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/utf8.js +99 -0
- package/bundle/node_modules/protons-runtime/dist/src/utils/writer.js +438 -0
- package/bundle/node_modules/uint8-varint/dist/src/index.js +124 -0
- package/bundle/node_modules/uint8arrays/dist/src/alloc.js +17 -0
- package/bundle/node_modules/uint8arrays/dist/src/concat.js +20 -0
- package/bundle/node_modules/uint8arrays/dist/src/from-string.js +19 -0
- package/bundle/node_modules/uint8arrays/dist/src/to-string.js +19 -0
- package/bundle/node_modules/uint8arrays/dist/src/util/as-uint8array.js +9 -0
- package/bundle/node_modules/uint8arrays/dist/src/util/bases.js +49 -0
- package/bundle/packages/core/dist/lib/connection_manager/connection_limiter.js +18 -0
- package/bundle/packages/core/dist/lib/connection_manager/connection_manager.js +24 -0
- package/bundle/packages/core/dist/lib/connection_manager/dialer.js +14 -0
- package/bundle/packages/core/dist/lib/connection_manager/discovery_dialer.js +14 -0
- package/bundle/packages/core/dist/lib/connection_manager/keep_alive_manager.js +15 -0
- package/bundle/packages/core/dist/lib/connection_manager/shard_reader.js +14 -0
- package/bundle/packages/core/dist/lib/filter/filter.js +28 -0
- package/bundle/packages/core/dist/lib/light_push/light_push.js +28 -0
- package/bundle/packages/core/dist/lib/message/version_0.js +172 -0
- package/bundle/packages/core/dist/lib/metadata/metadata.js +28 -0
- package/bundle/packages/core/dist/lib/store/store.js +24 -0
- package/bundle/packages/interfaces/dist/connection_manager.js +9 -0
- package/bundle/packages/interfaces/dist/health_status.js +17 -0
- package/bundle/packages/interfaces/dist/protocols.js +92 -0
- package/bundle/packages/interfaces/dist/waku.js +7 -0
- package/bundle/packages/proto/dist/generated/filter.js +447 -0
- package/bundle/packages/proto/dist/generated/filter_v2.js +426 -0
- package/bundle/packages/proto/dist/generated/light_push.js +550 -0
- package/bundle/packages/proto/dist/generated/message.js +215 -0
- package/bundle/packages/proto/dist/generated/metadata.js +132 -0
- package/bundle/packages/proto/dist/generated/peer_exchange.js +211 -0
- package/bundle/packages/proto/dist/generated/sds_message.js +172 -0
- package/bundle/packages/proto/dist/generated/store_v3.js +492 -0
- package/bundle/packages/proto/dist/generated/topic_only_message.js +63 -0
- package/bundle/packages/rln/dist/codec.js +92 -0
- package/bundle/packages/rln/dist/contract/constants.js +14 -7
- package/bundle/packages/rln/dist/contract/rln_base_contract.js +2 -1
- package/bundle/packages/rln/dist/contract/rln_contract.js +109 -0
- package/bundle/packages/rln/dist/credentials_manager.js +45 -4
- package/bundle/packages/rln/dist/identity.js +2 -1
- package/bundle/packages/rln/dist/keystore/keystore.js +30 -9
- package/bundle/packages/rln/dist/message.js +59 -0
- package/bundle/packages/rln/dist/proof.js +54 -0
- package/bundle/packages/rln/dist/resources/verification_key.js +112 -0
- package/bundle/packages/rln/dist/resources/witness_calculator.js +1 -1
- package/bundle/packages/rln/dist/rln.js +36 -4
- package/bundle/packages/rln/dist/root_tracker.js +76 -0
- package/bundle/packages/rln/dist/utils/bytes.js +70 -31
- package/bundle/packages/rln/dist/utils/epoch.js +23 -1
- package/bundle/packages/rln/dist/utils/hash.js +10 -0
- package/bundle/packages/rln/dist/zerokit.js +99 -2
- package/bundle/packages/utils/dist/bytes/index.js +31 -0
- package/bundle/resources/rln.wasm +0 -0
- package/bundle/resources/rln_final.zkey +0 -0
- package/bundle/resources/verification_key.d.ts +13 -0
- package/bundle/resources/verification_key.js +112 -0
- package/bundle/resources/witness_calculator.d.ts +7 -21
- package/bundle/resources/witness_calculator.js +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/codec.d.ts +40 -0
- package/dist/codec.js +79 -0
- package/dist/codec.js.map +1 -0
- package/dist/codec.test-utils.d.ts +37 -0
- package/dist/codec.test-utils.js +61 -0
- package/dist/codec.test-utils.js.map +1 -0
- package/dist/contract/constants.d.ts +10 -3
- package/dist/contract/constants.js +13 -6
- package/dist/contract/constants.js.map +1 -1
- package/dist/contract/index.d.ts +1 -0
- package/dist/contract/index.js +1 -0
- package/dist/contract/index.js.map +1 -1
- package/dist/contract/rln_base_contract.js +2 -1
- package/dist/contract/rln_base_contract.js.map +1 -1
- package/dist/contract/rln_contract.d.ts +17 -0
- package/dist/contract/rln_contract.js +107 -0
- package/dist/contract/rln_contract.js.map +1 -0
- package/dist/contract/test_setup.d.ts +26 -0
- package/dist/contract/test_setup.js +56 -0
- package/dist/contract/test_setup.js.map +1 -0
- package/dist/contract/test_utils.d.ts +39 -0
- package/dist/contract/test_utils.js +118 -0
- package/dist/contract/test_utils.js.map +1 -0
- package/dist/credentials_manager.d.ts +14 -2
- package/dist/credentials_manager.js +45 -4
- package/dist/credentials_manager.js.map +1 -1
- package/dist/identity.js +2 -1
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/keystore/keystore.js +30 -9
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/message.d.ts +19 -0
- package/dist/message.js +51 -0
- package/dist/message.js.map +1 -0
- package/dist/proof.d.ts +21 -0
- package/dist/proof.js +50 -0
- package/dist/proof.js.map +1 -0
- package/dist/resources/rln.wasm +0 -0
- package/dist/resources/rln_final.zkey +0 -0
- package/dist/resources/verification_key.d.ts +13 -0
- package/dist/resources/verification_key.js +112 -0
- package/dist/resources/witness_calculator.d.ts +7 -21
- package/dist/resources/witness_calculator.js +1 -1
- package/dist/rln.d.ts +9 -0
- package/dist/rln.js +32 -4
- package/dist/rln.js.map +1 -1
- package/dist/root_tracker.d.ts +10 -0
- package/dist/root_tracker.js +75 -0
- package/dist/root_tracker.js.map +1 -0
- package/dist/utils/bytes.d.ts +31 -9
- package/dist/utils/bytes.js +70 -31
- package/dist/utils/bytes.js.map +1 -1
- package/dist/zerokit.d.ts +11 -0
- package/dist/zerokit.js +97 -1
- package/dist/zerokit.js.map +1 -1
- package/package.json +1 -1
- package/src/codec.test-utils.ts +88 -0
- package/src/codec.ts +138 -0
- package/src/contract/constants.ts +16 -6
- package/src/contract/index.ts +1 -0
- package/src/contract/rln_base_contract.ts +2 -1
- package/src/contract/rln_contract.ts +147 -0
- package/src/contract/test_setup.ts +86 -0
- package/src/contract/test_utils.ts +179 -0
- package/src/credentials_manager.ts +72 -8
- package/src/identity.ts +2 -1
- package/src/index.ts +11 -1
- package/src/keystore/keystore.ts +32 -9
- package/src/message.ts +73 -0
- package/src/proof.ts +69 -0
- package/src/resources/verification_key.d.ts +13 -0
- package/src/resources/witness_calculator.d.ts +7 -21
- package/src/rln.ts +65 -5
- package/src/root_tracker.ts +92 -0
- package/src/utils/bytes.ts +73 -36
- 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
|
package/dist/zerokit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zerokit.js","sourceRoot":"","sources":["../src/zerokit.ts"],"names":[],"mappings":"
|
|
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-
|
|
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
|
-
|
|
23
|
-
|
|
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.
|
|
29
|
-
MAX_RATE: RATE_LIMIT_TIERS.
|
|
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;
|
package/src/contract/index.ts
CHANGED
|
@@ -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.
|
|
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
|
+
};
|