@waku/rln 0.1.0 → 0.1.1-0fbf6be
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/assets/rln_wasm_bg-a503e304.wasm +0 -0
- package/bundle/index.js +23020 -389
- package/dist/.tsbuildinfo +1 -1
- package/dist/byte_utils.d.ts +6 -0
- package/dist/byte_utils.js +9 -0
- package/dist/byte_utils.js.map +1 -1
- package/dist/codec.d.ts +5 -3
- package/dist/codec.js +8 -2
- package/dist/codec.js.map +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/constants.js +64 -11
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/keystore/cipher.d.ts +4 -0
- package/dist/keystore/cipher.js +28 -0
- package/dist/keystore/cipher.js.map +1 -0
- package/dist/keystore/credential_validation_generated.d.ts +8 -0
- package/dist/keystore/credential_validation_generated.js +121 -0
- package/dist/keystore/credential_validation_generated.js.map +1 -0
- package/dist/keystore/index.d.ts +2 -0
- package/dist/keystore/index.js +3 -0
- package/dist/keystore/index.js.map +1 -0
- package/dist/keystore/keystore.d.ts +50 -0
- package/dist/keystore/keystore.js +193 -0
- package/dist/keystore/keystore.js.map +1 -0
- package/dist/keystore/keystore_validation_generated.d.ts +8 -0
- package/dist/keystore/keystore_validation_generated.js +75 -0
- package/dist/keystore/keystore_validation_generated.js.map +1 -0
- package/dist/keystore/schema_validator.d.ts +2 -0
- package/dist/keystore/schema_validator.js +18 -0
- package/dist/keystore/schema_validator.js.map +1 -0
- package/dist/keystore/types.d.ts +9 -0
- package/dist/keystore/types.js +2 -0
- package/dist/keystore/types.js.map +1 -0
- package/dist/message.d.ts +3 -2
- package/dist/message.js +6 -3
- package/dist/message.js.map +1 -1
- package/dist/rln.js +4 -12
- package/dist/rln.js.map +1 -1
- package/dist/rln_contract.d.ts +28 -14
- package/dist/rln_contract.js +116 -28
- package/dist/rln_contract.js.map +1 -1
- package/package.json +23 -8
- package/src/byte_utils.ts +10 -0
- package/src/codec.ts +10 -2
- package/src/constants.ts +65 -11
- package/src/index.ts +10 -3
- package/src/message.ts +8 -3
- package/src/rln.ts +4 -13
- package/src/rln_contract.ts +187 -44
- package/bundle/assets/rln-fb4d7b4b.wasm +0 -0
- package/bundle/assets/rln_final-a641c06e.zkey +0 -0
- package/bundle/assets/rln_wasm_bg-0cccb7e0.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-27248f6c.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-3456ff62.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-4d82d6a4.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-543cb149.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-6f96f821.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-904d2abf.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-bbb6e96d.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-c26c7721.wasm +0 -0
- package/bundle/assets/rln_wasm_bg-d38ba0c1.wasm +0 -0
package/src/message.ts
CHANGED
@@ -14,7 +14,7 @@ export function toRLNSignal(contentTopic: string, msg: IMessage): Uint8Array {
|
|
14
14
|
}
|
15
15
|
|
16
16
|
export class RlnMessage<T extends IDecodedMessage> implements IDecodedMessage {
|
17
|
-
public
|
17
|
+
public pubsubTopic = "";
|
18
18
|
|
19
19
|
constructor(
|
20
20
|
public rlnInstance: RLNInstance,
|
@@ -22,11 +22,12 @@ export class RlnMessage<T extends IDecodedMessage> implements IDecodedMessage {
|
|
22
22
|
public rateLimitProof: IRateLimitProof | undefined
|
23
23
|
) {}
|
24
24
|
|
25
|
-
public verify(): boolean | undefined {
|
25
|
+
public verify(roots: Uint8Array[]): boolean | undefined {
|
26
26
|
return this.rateLimitProof
|
27
27
|
? this.rlnInstance.verifyWithRoots(
|
28
28
|
this.rateLimitProof,
|
29
|
-
toRLNSignal(this.msg.contentTopic, this.msg)
|
29
|
+
toRLNSignal(this.msg.contentTopic, this.msg),
|
30
|
+
...roots
|
30
31
|
) // this.rlnInstance.verifyRLNProof once issue status-im/nwaku#1248 is fixed
|
31
32
|
: undefined;
|
32
33
|
}
|
@@ -56,6 +57,10 @@ export class RlnMessage<T extends IDecodedMessage> implements IDecodedMessage {
|
|
56
57
|
return this.msg.ephemeral;
|
57
58
|
}
|
58
59
|
|
60
|
+
get meta(): Uint8Array | undefined {
|
61
|
+
return this.msg.meta;
|
62
|
+
}
|
63
|
+
|
59
64
|
get epoch(): number | undefined {
|
60
65
|
const bytes = this.msg.rateLimitProof?.epoch;
|
61
66
|
if (!bytes) return;
|
package/src/rln.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import type { IRateLimitProof } from "@waku/interfaces";
|
2
|
-
import init
|
2
|
+
import init from "@waku/zerokit-rln-wasm";
|
3
|
+
import * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
3
4
|
|
4
|
-
import { writeUIntLE } from "./byte_utils.js";
|
5
|
+
import { buildBigIntFromUint8Array, writeUIntLE } from "./byte_utils.js";
|
5
6
|
import { dateToEpoch, epochIntToBytes } from "./epoch.js";
|
6
7
|
import verificationKey from "./resources/verification_key.js";
|
7
8
|
import * as wc from "./witness_calculator.js";
|
@@ -26,16 +27,6 @@ function concatenate(...input: Uint8Array[]): Uint8Array {
|
|
26
27
|
return result;
|
27
28
|
}
|
28
29
|
|
29
|
-
/**
|
30
|
-
* Transforms Uint8Array into BigInt
|
31
|
-
* @param array: Uint8Array
|
32
|
-
* @returns BigInt
|
33
|
-
*/
|
34
|
-
function buildBigIntFromUint8Array(array: Uint8Array): bigint {
|
35
|
-
const dataView = new DataView(array.buffer);
|
36
|
-
return dataView.getBigUint64(0, true);
|
37
|
-
}
|
38
|
-
|
39
30
|
const stringEncoder = new TextEncoder();
|
40
31
|
|
41
32
|
const DEPTH = 20;
|
@@ -57,7 +48,7 @@ async function loadZkey(): Promise<Uint8Array> {
|
|
57
48
|
* @returns RLNInstance
|
58
49
|
*/
|
59
50
|
export async function create(): Promise<RLNInstance> {
|
60
|
-
await init();
|
51
|
+
await (init as any)?.();
|
61
52
|
zerokitRLN.init_panic_hook();
|
62
53
|
const witnessCalculator = await loadWitnessCalculator();
|
63
54
|
const zkey = await loadZkey();
|
package/src/rln_contract.ts
CHANGED
@@ -1,18 +1,27 @@
|
|
1
1
|
import { ethers } from "ethers";
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { RLN_REGISTRY_ABI, RLN_STORAGE_ABI } from "./constants.js";
|
4
4
|
import { IdentityCredential, RLNInstance } from "./rln.js";
|
5
|
+
import { MerkleRootTracker } from "./root_tracker.js";
|
5
6
|
|
6
7
|
type Member = {
|
7
|
-
|
8
|
-
index:
|
8
|
+
idCommitment: string;
|
9
|
+
index: ethers.BigNumber;
|
9
10
|
};
|
10
11
|
|
11
|
-
type
|
12
|
-
|
13
|
-
|
12
|
+
type Provider = ethers.Signer | ethers.providers.Provider;
|
13
|
+
|
14
|
+
type RLNContractOptions = {
|
15
|
+
provider: Provider;
|
16
|
+
registryAddress: string;
|
17
|
+
};
|
18
|
+
|
19
|
+
type RLNStorageOptions = {
|
20
|
+
storageIndex?: number;
|
14
21
|
};
|
15
22
|
|
23
|
+
type RLNContractInitOptions = RLNContractOptions & RLNStorageOptions;
|
24
|
+
|
16
25
|
type FetchMembersOptions = {
|
17
26
|
fromBlock?: number;
|
18
27
|
fetchRange?: number;
|
@@ -20,34 +29,86 @@ type FetchMembersOptions = {
|
|
20
29
|
};
|
21
30
|
|
22
31
|
export class RLNContract {
|
23
|
-
private
|
24
|
-
private
|
32
|
+
private registryContract: ethers.Contract;
|
33
|
+
private merkleRootTracker: MerkleRootTracker;
|
25
34
|
|
26
|
-
private
|
35
|
+
private deployBlock: undefined | number;
|
36
|
+
private storageIndex: undefined | number;
|
37
|
+
private storageContract: undefined | ethers.Contract;
|
38
|
+
private _membersFilter: undefined | ethers.EventFilter;
|
39
|
+
|
40
|
+
private _members: Map<number, Member> = new Map();
|
27
41
|
|
28
42
|
public static async init(
|
29
43
|
rlnInstance: RLNInstance,
|
30
|
-
options:
|
44
|
+
options: RLNContractInitOptions
|
31
45
|
): Promise<RLNContract> {
|
32
|
-
const rlnContract = new RLNContract(options);
|
46
|
+
const rlnContract = new RLNContract(rlnInstance, options);
|
33
47
|
|
48
|
+
await rlnContract.initStorageContract(options.provider);
|
34
49
|
await rlnContract.fetchMembers(rlnInstance);
|
35
50
|
rlnContract.subscribeToMembers(rlnInstance);
|
36
51
|
|
37
52
|
return rlnContract;
|
38
53
|
}
|
39
54
|
|
40
|
-
constructor(
|
41
|
-
|
42
|
-
|
55
|
+
constructor(
|
56
|
+
rlnInstance: RLNInstance,
|
57
|
+
{ registryAddress, provider }: RLNContractOptions
|
58
|
+
) {
|
59
|
+
const initialRoot = rlnInstance.getMerkleRoot();
|
60
|
+
|
61
|
+
this.registryContract = new ethers.Contract(
|
62
|
+
registryAddress,
|
63
|
+
RLN_REGISTRY_ABI,
|
64
|
+
provider
|
65
|
+
);
|
66
|
+
this.merkleRootTracker = new MerkleRootTracker(10000, initialRoot);
|
67
|
+
}
|
68
|
+
|
69
|
+
private async initStorageContract(
|
70
|
+
provider: Provider,
|
71
|
+
options: RLNStorageOptions = {}
|
72
|
+
): Promise<void> {
|
73
|
+
const storageIndex = options?.storageIndex
|
74
|
+
? options.storageIndex
|
75
|
+
: await this.registryContract.usingStorageIndex();
|
76
|
+
const storageAddress = await this.registryContract.storages(storageIndex);
|
77
|
+
|
78
|
+
if (!storageAddress || storageAddress === ethers.constants.AddressZero) {
|
79
|
+
throw Error("No RLN Storage initialized on registry contract.");
|
80
|
+
}
|
81
|
+
|
82
|
+
this.storageIndex = storageIndex;
|
83
|
+
this.storageContract = new ethers.Contract(
|
84
|
+
storageAddress,
|
85
|
+
RLN_STORAGE_ABI,
|
86
|
+
provider
|
87
|
+
);
|
88
|
+
this._membersFilter = this.storageContract.filters.MemberRegistered();
|
89
|
+
|
90
|
+
this.deployBlock = await this.storageContract.deployedBlockNumber();
|
43
91
|
}
|
44
92
|
|
45
93
|
public get contract(): ethers.Contract {
|
46
|
-
|
94
|
+
if (!this.storageContract) {
|
95
|
+
throw Error("Storage contract was not initialized");
|
96
|
+
}
|
97
|
+
return this.storageContract as ethers.Contract;
|
47
98
|
}
|
48
99
|
|
49
100
|
public get members(): Member[] {
|
50
|
-
|
101
|
+
const sortedMembers = Array.from(this._members.values()).sort(
|
102
|
+
(left, right) => left.index.toNumber() - right.index.toNumber()
|
103
|
+
);
|
104
|
+
return sortedMembers;
|
105
|
+
}
|
106
|
+
|
107
|
+
private get membersFilter(): ethers.EventFilter {
|
108
|
+
if (!this._membersFilter) {
|
109
|
+
throw Error("Members filter was not initialized.");
|
110
|
+
}
|
111
|
+
return this._membersFilter as ethers.EventFilter;
|
51
112
|
}
|
52
113
|
|
53
114
|
public async fetchMembers(
|
@@ -55,45 +116,103 @@ export class RLNContract {
|
|
55
116
|
options: FetchMembersOptions = {}
|
56
117
|
): Promise<void> {
|
57
118
|
const registeredMemberEvents = await queryFilter(this.contract, {
|
119
|
+
fromBlock: this.deployBlock,
|
58
120
|
...options,
|
59
121
|
membersFilter: this.membersFilter,
|
60
122
|
});
|
61
|
-
|
62
|
-
for (const event of registeredMemberEvents) {
|
63
|
-
this.addMemberFromEvent(rlnInstance, event);
|
64
|
-
}
|
123
|
+
this.processEvents(rlnInstance, registeredMemberEvents);
|
65
124
|
}
|
66
125
|
|
67
|
-
public
|
68
|
-
|
69
|
-
|
70
|
-
|
126
|
+
public processEvents(rlnInstance: RLNInstance, events: ethers.Event[]): void {
|
127
|
+
const toRemoveTable = new Map<number, number[]>();
|
128
|
+
const toInsertTable = new Map<number, ethers.Event[]>();
|
129
|
+
|
130
|
+
events.forEach((evt) => {
|
131
|
+
if (!evt.args) {
|
132
|
+
return;
|
133
|
+
}
|
134
|
+
|
135
|
+
if (evt.removed) {
|
136
|
+
const index: ethers.BigNumber = evt.args.index;
|
137
|
+
const toRemoveVal = toRemoveTable.get(evt.blockNumber);
|
138
|
+
if (toRemoveVal != undefined) {
|
139
|
+
toRemoveVal.push(index.toNumber());
|
140
|
+
toRemoveTable.set(evt.blockNumber, toRemoveVal);
|
141
|
+
} else {
|
142
|
+
toRemoveTable.set(evt.blockNumber, [index.toNumber()]);
|
143
|
+
}
|
144
|
+
} else {
|
145
|
+
let eventsPerBlock = toInsertTable.get(evt.blockNumber);
|
146
|
+
if (eventsPerBlock == undefined) {
|
147
|
+
eventsPerBlock = [];
|
148
|
+
}
|
149
|
+
|
150
|
+
eventsPerBlock.push(evt);
|
151
|
+
toInsertTable.set(evt.blockNumber, eventsPerBlock);
|
152
|
+
}
|
153
|
+
});
|
154
|
+
|
155
|
+
this.removeMembers(rlnInstance, toRemoveTable);
|
156
|
+
this.insertMembers(rlnInstance, toInsertTable);
|
71
157
|
}
|
72
158
|
|
73
|
-
private
|
159
|
+
private insertMembers(
|
74
160
|
rlnInstance: RLNInstance,
|
75
|
-
|
161
|
+
toInsert: Map<number, ethers.Event[]>
|
76
162
|
): void {
|
77
|
-
|
78
|
-
|
79
|
-
|
163
|
+
toInsert.forEach((events: ethers.Event[], blockNumber: number) => {
|
164
|
+
events.forEach((evt) => {
|
165
|
+
const _idCommitment = evt?.args?.idCommitment;
|
166
|
+
const index: ethers.BigNumber = evt?.args?.index;
|
167
|
+
|
168
|
+
if (!_idCommitment || !index) {
|
169
|
+
return;
|
170
|
+
}
|
171
|
+
|
172
|
+
const idCommitment = ethers.utils.zeroPad(
|
173
|
+
ethers.utils.arrayify(_idCommitment),
|
174
|
+
32
|
175
|
+
);
|
176
|
+
rlnInstance.insertMember(idCommitment);
|
177
|
+
this._members.set(index.toNumber(), {
|
178
|
+
index,
|
179
|
+
idCommitment:
|
180
|
+
_idCommitment?._hex || ethers.utils.hexlify(idCommitment),
|
181
|
+
});
|
182
|
+
});
|
183
|
+
|
184
|
+
const currentRoot = rlnInstance.getMerkleRoot();
|
185
|
+
this.merkleRootTracker.pushRoot(blockNumber, currentRoot);
|
186
|
+
});
|
187
|
+
}
|
80
188
|
|
81
|
-
|
82
|
-
|
189
|
+
private removeMembers(
|
190
|
+
rlnInstance: RLNInstance,
|
191
|
+
toRemove: Map<number, number[]>
|
192
|
+
): void {
|
193
|
+
const removeDescending = new Map([...toRemove].sort().reverse());
|
194
|
+
removeDescending.forEach((indexes: number[], blockNumber: number) => {
|
195
|
+
indexes.forEach((index) => {
|
196
|
+
if (this._members.has(index)) {
|
197
|
+
this._members.delete(index);
|
198
|
+
}
|
199
|
+
rlnInstance.deleteMember(index);
|
200
|
+
});
|
83
201
|
|
84
|
-
|
202
|
+
this.merkleRootTracker.backFill(blockNumber);
|
203
|
+
});
|
204
|
+
}
|
85
205
|
|
86
|
-
|
87
|
-
|
88
|
-
|
206
|
+
public subscribeToMembers(rlnInstance: RLNInstance): void {
|
207
|
+
this.contract.on(this.membersFilter, (_pubkey, _index, event) =>
|
208
|
+
this.processEvents(rlnInstance, [event])
|
89
209
|
);
|
90
|
-
rlnInstance.insertMember(idCommitment);
|
91
210
|
}
|
92
211
|
|
93
212
|
public async registerWithSignature(
|
94
213
|
rlnInstance: RLNInstance,
|
95
214
|
signature: string
|
96
|
-
): Promise<
|
215
|
+
): Promise<Member | undefined> {
|
97
216
|
const identityCredential =
|
98
217
|
await rlnInstance.generateSeededIdentityCredential(signature);
|
99
218
|
|
@@ -102,16 +221,40 @@ export class RLNContract {
|
|
102
221
|
|
103
222
|
public async registerWithKey(
|
104
223
|
credential: IdentityCredential
|
105
|
-
): Promise<
|
106
|
-
|
107
|
-
|
224
|
+
): Promise<Member | undefined> {
|
225
|
+
if (this.storageIndex === undefined) {
|
226
|
+
throw Error(
|
227
|
+
"Cannot register credential, no storage contract index found."
|
228
|
+
);
|
229
|
+
}
|
108
230
|
const txRegisterResponse: ethers.ContractTransaction =
|
109
|
-
await this.
|
110
|
-
|
111
|
-
|
231
|
+
await this.registryContract["register(uint16,uint256)"](
|
232
|
+
this.storageIndex,
|
233
|
+
credential.IDCommitmentBigInt,
|
234
|
+
{ gasLimit: 100000 }
|
235
|
+
);
|
112
236
|
const txRegisterReceipt = await txRegisterResponse.wait();
|
113
237
|
|
114
|
-
|
238
|
+
// assumption: register(uint16,uint256) emits one event
|
239
|
+
const memberRegistered = txRegisterReceipt?.events?.[0];
|
240
|
+
|
241
|
+
if (!memberRegistered) {
|
242
|
+
return undefined;
|
243
|
+
}
|
244
|
+
|
245
|
+
const decodedData = this.contract.interface.decodeEventLog(
|
246
|
+
"MemberRegistered",
|
247
|
+
memberRegistered.data
|
248
|
+
);
|
249
|
+
|
250
|
+
return {
|
251
|
+
idCommitment: decodedData.idCommitment,
|
252
|
+
index: decodedData.index,
|
253
|
+
};
|
254
|
+
}
|
255
|
+
|
256
|
+
public roots(): Uint8Array[] {
|
257
|
+
return this.merkleRootTracker.roots();
|
115
258
|
}
|
116
259
|
}
|
117
260
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|