@waku/rln 0.1.2 → 0.1.3
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/index.js +40916 -39697
- package/dist/codec.d.ts +2 -1
- package/dist/codec.js +7 -1
- package/dist/codec.js.map +1 -1
- package/dist/{constants.js → contract/constants.js} +3 -3
- package/dist/contract/constants.js.map +1 -0
- package/dist/contract/index.d.ts +2 -0
- package/dist/contract/index.js +3 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/{rln_contract.d.ts → contract/rln_contract.d.ts} +3 -2
- package/dist/{rln_contract.js → contract/rln_contract.js} +24 -18
- package/dist/contract/rln_contract.js.map +1 -0
- package/dist/identity.d.ts +9 -0
- package/dist/identity.js +24 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/keystore/cipher.js +1 -1
- package/dist/keystore/cipher.js.map +1 -1
- package/dist/keystore/credential_validation_generated.js.map +1 -1
- package/dist/keystore/keystore.js +21 -18
- package/dist/keystore/keystore.js.map +1 -1
- package/dist/keystore/keystore_validation_generated.js.map +1 -1
- package/dist/keystore/schema_validator.js.map +1 -1
- package/dist/keystore/types.d.ts +1 -1
- package/dist/message.js +7 -4
- package/dist/message.js.map +1 -1
- package/dist/proof.d.ts +21 -0
- package/dist/proof.js +49 -0
- package/dist/proof.js.map +1 -0
- package/dist/resources/verification_key.d.ts +9 -9
- package/dist/resources/witness_calculator.js.map +1 -0
- package/dist/rln.d.ts +6 -48
- package/dist/rln.js +25 -194
- package/dist/rln.js.map +1 -1
- package/dist/root_tracker.js +5 -2
- package/dist/root_tracker.js.map +1 -1
- package/dist/{byte_utils.d.ts → utils/bytes.d.ts} +7 -1
- package/dist/{byte_utils.js → utils/bytes.js} +21 -3
- package/dist/utils/bytes.js.map +1 -0
- package/dist/utils/epoch.js.map +1 -0
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +13 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/{metamask.js → utils/metamask.js} +1 -0
- package/dist/utils/metamask.js.map +1 -0
- package/dist/zerokit.d.ts +19 -0
- package/dist/zerokit.js +105 -0
- package/dist/zerokit.js.map +1 -0
- package/package.json +19 -24
- package/src/codec.ts +8 -4
- package/src/identity.ts +27 -0
- package/src/index.ts +8 -12
- package/src/message.ts +4 -4
- package/src/proof.ts +67 -0
- package/src/rln.ts +32 -308
- package/src/root_tracker.ts +4 -1
- package/src/zerokit.ts +181 -0
- package/dist/.tsbuildinfo +0 -1
- package/dist/byte_utils.js.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/epoch.js.map +0 -1
- package/dist/metamask.js.map +0 -1
- package/dist/rln_contract.js.map +0 -1
- package/dist/witness_calculator.js.map +0 -1
- package/src/byte_utils.ts +0 -63
- package/src/constants.ts +0 -68
- package/src/epoch.ts +0 -30
- package/src/metamask.ts +0 -16
- package/src/rln_contract.ts +0 -350
- package/src/witness_calculator.d.ts +0 -8
- package/src/witness_calculator.js +0 -335
- /package/dist/{constants.d.ts → contract/constants.d.ts} +0 -0
- /package/dist/{witness_calculator.d.ts → resources/witness_calculator.d.ts} +0 -0
- /package/dist/{witness_calculator.js → resources/witness_calculator.js} +0 -0
- /package/dist/{epoch.d.ts → utils/epoch.d.ts} +0 -0
- /package/dist/{epoch.js → utils/epoch.js} +0 -0
- /package/dist/{metamask.d.ts → utils/metamask.d.ts} +0 -0
package/src/rln.ts
CHANGED
@@ -1,53 +1,32 @@
|
|
1
1
|
import { createDecoder, createEncoder } from "@waku/core";
|
2
|
-
import type { IRateLimitProof } from "@waku/interfaces";
|
3
2
|
import type {
|
4
3
|
ContentTopic,
|
5
4
|
IDecodedMessage,
|
6
|
-
EncoderOptions as WakuEncoderOptions
|
5
|
+
EncoderOptions as WakuEncoderOptions
|
7
6
|
} from "@waku/interfaces";
|
8
7
|
import init from "@waku/zerokit-rln-wasm";
|
9
8
|
import * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
10
9
|
import { ethers } from "ethers";
|
11
10
|
|
12
|
-
import {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
import {
|
12
|
+
createRLNDecoder,
|
13
|
+
createRLNEncoder,
|
14
|
+
type RLNDecoder,
|
15
|
+
type RLNEncoder
|
16
|
+
} from "./codec.js";
|
17
|
+
import { RLNContract, SEPOLIA_CONTRACT } from "./contract/index.js";
|
18
|
+
import { IdentityCredential } from "./identity.js";
|
17
19
|
import { Keystore } from "./keystore/index.js";
|
18
20
|
import type {
|
19
21
|
DecryptedCredentials,
|
20
|
-
EncryptedCredentials
|
22
|
+
EncryptedCredentials
|
21
23
|
} from "./keystore/index.js";
|
22
24
|
import { KeystoreEntity, Password } from "./keystore/types.js";
|
23
|
-
import { extractMetaMaskSigner } from "./metamask.js";
|
24
25
|
import verificationKey from "./resources/verification_key.js";
|
25
|
-
import
|
26
|
-
import
|
27
|
-
import {
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Concatenate Uint8Arrays
|
31
|
-
* @param input
|
32
|
-
* @returns concatenation of all Uint8Array received as input
|
33
|
-
*/
|
34
|
-
function concatenate(...input: Uint8Array[]): Uint8Array {
|
35
|
-
let totalLength = 0;
|
36
|
-
for (const arr of input) {
|
37
|
-
totalLength += arr.length;
|
38
|
-
}
|
39
|
-
const result = new Uint8Array(totalLength);
|
40
|
-
let offset = 0;
|
41
|
-
for (const arr of input) {
|
42
|
-
result.set(arr, offset);
|
43
|
-
offset += arr.length;
|
44
|
-
}
|
45
|
-
return result;
|
46
|
-
}
|
47
|
-
|
48
|
-
const stringEncoder = new TextEncoder();
|
49
|
-
|
50
|
-
const DEPTH = 20;
|
26
|
+
import * as wc from "./resources/witness_calculator.js";
|
27
|
+
import { WitnessCalculator } from "./resources/witness_calculator.js";
|
28
|
+
import { extractMetaMaskSigner } from "./utils/index.js";
|
29
|
+
import { Zerokit } from "./zerokit.js";
|
51
30
|
|
52
31
|
async function loadWitnessCalculator(): Promise<WitnessCalculator> {
|
53
32
|
const url = new URL("./resources/rln.wasm", import.meta.url);
|
@@ -66,114 +45,21 @@ async function loadZkey(): Promise<Uint8Array> {
|
|
66
45
|
* @returns RLNInstance
|
67
46
|
*/
|
68
47
|
export async function create(): Promise<RLNInstance> {
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
69
49
|
await (init as any)?.();
|
70
50
|
zerokitRLN.init_panic_hook();
|
51
|
+
|
71
52
|
const witnessCalculator = await loadWitnessCalculator();
|
72
53
|
const zkey = await loadZkey();
|
73
|
-
const vkey = stringEncoder.encode(JSON.stringify(verificationKey));
|
74
|
-
const zkRLN = zerokitRLN.newRLN(DEPTH, zkey, vkey);
|
75
|
-
return new RLNInstance(zkRLN, witnessCalculator);
|
76
|
-
}
|
77
54
|
|
78
|
-
|
79
|
-
|
80
|
-
public readonly IDTrapdoor: Uint8Array,
|
81
|
-
public readonly IDNullifier: Uint8Array,
|
82
|
-
public readonly IDSecretHash: Uint8Array,
|
83
|
-
public readonly IDCommitment: Uint8Array,
|
84
|
-
public readonly IDCommitmentBigInt: bigint
|
85
|
-
) {}
|
86
|
-
|
87
|
-
static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
88
|
-
const idTrapdoor = memKeys.subarray(0, 32);
|
89
|
-
const idNullifier = memKeys.subarray(32, 64);
|
90
|
-
const idSecretHash = memKeys.subarray(64, 96);
|
91
|
-
const idCommitment = memKeys.subarray(96);
|
92
|
-
const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment);
|
93
|
-
|
94
|
-
return new IdentityCredential(
|
95
|
-
idTrapdoor,
|
96
|
-
idNullifier,
|
97
|
-
idSecretHash,
|
98
|
-
idCommitment,
|
99
|
-
idCommitmentBigInt
|
100
|
-
);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
|
104
|
-
const proofOffset = 128;
|
105
|
-
const rootOffset = proofOffset + 32;
|
106
|
-
const epochOffset = rootOffset + 32;
|
107
|
-
const shareXOffset = epochOffset + 32;
|
108
|
-
const shareYOffset = shareXOffset + 32;
|
109
|
-
const nullifierOffset = shareYOffset + 32;
|
110
|
-
const rlnIdentifierOffset = nullifierOffset + 32;
|
111
|
-
|
112
|
-
export class ProofMetadata {
|
113
|
-
constructor(
|
114
|
-
public readonly nullifier: Uint8Array,
|
115
|
-
public readonly shareX: Uint8Array,
|
116
|
-
public readonly shareY: Uint8Array,
|
117
|
-
public readonly externalNullifier: Uint8Array
|
118
|
-
) {}
|
119
|
-
}
|
120
|
-
export class Proof implements IRateLimitProof {
|
121
|
-
readonly proof: Uint8Array;
|
122
|
-
readonly merkleRoot: Uint8Array;
|
123
|
-
readonly epoch: Uint8Array;
|
124
|
-
readonly shareX: Uint8Array;
|
125
|
-
readonly shareY: Uint8Array;
|
126
|
-
readonly nullifier: Uint8Array;
|
127
|
-
readonly rlnIdentifier: Uint8Array;
|
128
|
-
|
129
|
-
constructor(proofBytes: Uint8Array) {
|
130
|
-
if (proofBytes.length < rlnIdentifierOffset) throw "invalid proof";
|
131
|
-
// parse the proof as proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32>
|
132
|
-
this.proof = proofBytes.subarray(0, proofOffset);
|
133
|
-
this.merkleRoot = proofBytes.subarray(proofOffset, rootOffset);
|
134
|
-
this.epoch = proofBytes.subarray(rootOffset, epochOffset);
|
135
|
-
this.shareX = proofBytes.subarray(epochOffset, shareXOffset);
|
136
|
-
this.shareY = proofBytes.subarray(shareXOffset, shareYOffset);
|
137
|
-
this.nullifier = proofBytes.subarray(shareYOffset, nullifierOffset);
|
138
|
-
this.rlnIdentifier = proofBytes.subarray(
|
139
|
-
nullifierOffset,
|
140
|
-
rlnIdentifierOffset
|
141
|
-
);
|
142
|
-
}
|
143
|
-
|
144
|
-
extractMetadata(): ProofMetadata {
|
145
|
-
const externalNullifier = poseidonHash(this.epoch, this.rlnIdentifier);
|
146
|
-
return new ProofMetadata(
|
147
|
-
this.nullifier,
|
148
|
-
this.shareX,
|
149
|
-
this.shareY,
|
150
|
-
externalNullifier
|
151
|
-
);
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
export function proofToBytes(p: IRateLimitProof): Uint8Array {
|
156
|
-
return concatenate(
|
157
|
-
p.proof,
|
158
|
-
p.merkleRoot,
|
159
|
-
p.epoch,
|
160
|
-
p.shareX,
|
161
|
-
p.shareY,
|
162
|
-
p.nullifier,
|
163
|
-
p.rlnIdentifier
|
164
|
-
);
|
165
|
-
}
|
55
|
+
const stringEncoder = new TextEncoder();
|
56
|
+
const vkey = stringEncoder.encode(JSON.stringify(verificationKey));
|
166
57
|
|
167
|
-
|
168
|
-
const
|
169
|
-
const
|
170
|
-
return zerokitRLN.poseidonHash(lenPrefixedData);
|
171
|
-
}
|
58
|
+
const DEPTH = 20;
|
59
|
+
const zkRLN = zerokitRLN.newRLN(DEPTH, zkey, vkey);
|
60
|
+
const zerokit = new Zerokit(zkRLN, witnessCalculator);
|
172
61
|
|
173
|
-
|
174
|
-
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
|
175
|
-
const lenPrefixedData = concatenate(inputLen, input);
|
176
|
-
return zerokitRLN.hash(lenPrefixedData);
|
62
|
+
return new RLNInstance(zerokit);
|
177
63
|
}
|
178
64
|
|
179
65
|
type StartRLNOptions = {
|
@@ -210,10 +96,7 @@ export class RLNInstance {
|
|
210
96
|
private keystore = Keystore.create();
|
211
97
|
private _credentials: undefined | DecryptedCredentials;
|
212
98
|
|
213
|
-
constructor(
|
214
|
-
private zkRLN: number,
|
215
|
-
private witnessCalculator: WitnessCalculator
|
216
|
-
) {}
|
99
|
+
constructor(public zerokit: Zerokit) {}
|
217
100
|
|
218
101
|
public get contract(): undefined | RLNContract {
|
219
102
|
return this._contract;
|
@@ -246,7 +129,7 @@ export class RLNInstance {
|
|
246
129
|
this._signer = signer!;
|
247
130
|
this._contract = await RLNContract.init(this, {
|
248
131
|
registryAddress: registryAddress!,
|
249
|
-
signer: signer
|
132
|
+
signer: signer!
|
250
133
|
});
|
251
134
|
this.started = true;
|
252
135
|
} finally {
|
@@ -279,7 +162,7 @@ export class RLNInstance {
|
|
279
162
|
|
280
163
|
return {
|
281
164
|
signer,
|
282
|
-
registryAddress
|
165
|
+
registryAddress
|
283
166
|
};
|
284
167
|
}
|
285
168
|
|
@@ -307,7 +190,7 @@ export class RLNInstance {
|
|
307
190
|
|
308
191
|
return {
|
309
192
|
keystore,
|
310
|
-
credentials: decryptedCredentials
|
193
|
+
credentials: decryptedCredentials
|
311
194
|
};
|
312
195
|
}
|
313
196
|
|
@@ -321,7 +204,9 @@ export class RLNInstance {
|
|
321
204
|
let identity = "identity" in options && options.identity;
|
322
205
|
|
323
206
|
if ("signature" in options) {
|
324
|
-
identity =
|
207
|
+
identity = this.zerokit.generateSeededIdentityCredential(
|
208
|
+
options.signature
|
209
|
+
);
|
325
210
|
}
|
326
211
|
|
327
212
|
if (!identity) {
|
@@ -359,7 +244,7 @@ export class RLNInstance {
|
|
359
244
|
encoder: createEncoder(options),
|
360
245
|
rlnInstance: this,
|
361
246
|
index: credentials.membership.treeIndex,
|
362
|
-
credential: credentials.identity
|
247
|
+
credential: credentials.identity
|
363
248
|
});
|
364
249
|
}
|
365
250
|
|
@@ -381,7 +266,7 @@ export class RLNInstance {
|
|
381
266
|
}
|
382
267
|
|
383
268
|
const chainId = credentials.membership.chainId;
|
384
|
-
const network = await this._contract.registry.getNetwork();
|
269
|
+
const network = await this._contract.registry.provider.getNetwork();
|
385
270
|
const currentChainId = network.chainId;
|
386
271
|
if (chainId !== currentChainId) {
|
387
272
|
throw Error(
|
@@ -395,168 +280,7 @@ export class RLNInstance {
|
|
395
280
|
): RLNDecoder<IDecodedMessage> {
|
396
281
|
return createRLNDecoder({
|
397
282
|
rlnInstance: this,
|
398
|
-
decoder: createDecoder(contentTopic)
|
283
|
+
decoder: createDecoder(contentTopic)
|
399
284
|
});
|
400
285
|
}
|
401
|
-
|
402
|
-
generateIdentityCredentials(): IdentityCredential {
|
403
|
-
const memKeys = zerokitRLN.generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm
|
404
|
-
return IdentityCredential.fromBytes(memKeys);
|
405
|
-
}
|
406
|
-
|
407
|
-
generateSeededIdentityCredential(seed: string): IdentityCredential {
|
408
|
-
const seedBytes = stringEncoder.encode(seed);
|
409
|
-
// TODO: rename this function in zerokit rln-wasm
|
410
|
-
const memKeys = zerokitRLN.generateSeededExtendedMembershipKey(
|
411
|
-
this.zkRLN,
|
412
|
-
seedBytes
|
413
|
-
);
|
414
|
-
return IdentityCredential.fromBytes(memKeys);
|
415
|
-
}
|
416
|
-
|
417
|
-
insertMember(idCommitment: Uint8Array): void {
|
418
|
-
zerokitRLN.insertMember(this.zkRLN, idCommitment);
|
419
|
-
}
|
420
|
-
|
421
|
-
insertMembers(index: number, ...idCommitments: Array<Uint8Array>): void {
|
422
|
-
// serializes a seq of IDCommitments to a byte seq
|
423
|
-
// the order of serialization is |id_commitment_len<8>|id_commitment<var>|
|
424
|
-
const idCommitmentLen = writeUIntLE(
|
425
|
-
new Uint8Array(8),
|
426
|
-
idCommitments.length,
|
427
|
-
0,
|
428
|
-
8
|
429
|
-
);
|
430
|
-
const idCommitmentBytes = concatenate(idCommitmentLen, ...idCommitments);
|
431
|
-
zerokitRLN.setLeavesFrom(this.zkRLN, index, idCommitmentBytes);
|
432
|
-
}
|
433
|
-
|
434
|
-
deleteMember(index: number): void {
|
435
|
-
zerokitRLN.deleteLeaf(this.zkRLN, index);
|
436
|
-
}
|
437
|
-
|
438
|
-
getMerkleRoot(): Uint8Array {
|
439
|
-
return zerokitRLN.getRoot(this.zkRLN);
|
440
|
-
}
|
441
|
-
|
442
|
-
serializeMessage(
|
443
|
-
uint8Msg: Uint8Array,
|
444
|
-
memIndex: number,
|
445
|
-
epoch: Uint8Array,
|
446
|
-
idKey: Uint8Array
|
447
|
-
): Uint8Array {
|
448
|
-
// calculate message length
|
449
|
-
const msgLen = writeUIntLE(new Uint8Array(8), uint8Msg.length, 0, 8);
|
450
|
-
|
451
|
-
// Converting index to LE bytes
|
452
|
-
const memIndexBytes = writeUIntLE(new Uint8Array(8), memIndex, 0, 8);
|
453
|
-
|
454
|
-
// [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
455
|
-
return concatenate(idKey, memIndexBytes, epoch, msgLen, uint8Msg);
|
456
|
-
}
|
457
|
-
|
458
|
-
async generateRLNProof(
|
459
|
-
msg: Uint8Array,
|
460
|
-
index: number,
|
461
|
-
epoch: Uint8Array | Date | undefined,
|
462
|
-
idSecretHash: Uint8Array
|
463
|
-
): Promise<IRateLimitProof> {
|
464
|
-
if (epoch == undefined) {
|
465
|
-
epoch = epochIntToBytes(dateToEpoch(new Date()));
|
466
|
-
} else if (epoch instanceof Date) {
|
467
|
-
epoch = epochIntToBytes(dateToEpoch(epoch));
|
468
|
-
}
|
469
|
-
|
470
|
-
if (epoch.length != 32) throw "invalid epoch";
|
471
|
-
if (idSecretHash.length != 32) throw "invalid id secret hash";
|
472
|
-
if (index < 0) throw "index must be >= 0";
|
473
|
-
|
474
|
-
const serialized_msg = this.serializeMessage(
|
475
|
-
msg,
|
476
|
-
index,
|
477
|
-
epoch,
|
478
|
-
idSecretHash
|
479
|
-
);
|
480
|
-
const rlnWitness = zerokitRLN.getSerializedRLNWitness(
|
481
|
-
this.zkRLN,
|
482
|
-
serialized_msg
|
483
|
-
);
|
484
|
-
const inputs = zerokitRLN.RLNWitnessToJson(this.zkRLN, rlnWitness);
|
485
|
-
const calculatedWitness = await this.witnessCalculator.calculateWitness(
|
486
|
-
inputs,
|
487
|
-
false
|
488
|
-
); // no sanity check being used in zerokit
|
489
|
-
|
490
|
-
const proofBytes = zerokitRLN.generate_rln_proof_with_witness(
|
491
|
-
this.zkRLN,
|
492
|
-
calculatedWitness,
|
493
|
-
rlnWitness
|
494
|
-
);
|
495
|
-
|
496
|
-
return new Proof(proofBytes);
|
497
|
-
}
|
498
|
-
|
499
|
-
verifyRLNProof(
|
500
|
-
proof: IRateLimitProof | Uint8Array,
|
501
|
-
msg: Uint8Array
|
502
|
-
): boolean {
|
503
|
-
let pBytes: Uint8Array;
|
504
|
-
if (proof instanceof Uint8Array) {
|
505
|
-
pBytes = proof;
|
506
|
-
} else {
|
507
|
-
pBytes = proofToBytes(proof);
|
508
|
-
}
|
509
|
-
|
510
|
-
// calculate message length
|
511
|
-
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
512
|
-
|
513
|
-
return zerokitRLN.verifyRLNProof(
|
514
|
-
this.zkRLN,
|
515
|
-
concatenate(pBytes, msgLen, msg)
|
516
|
-
);
|
517
|
-
}
|
518
|
-
|
519
|
-
verifyWithRoots(
|
520
|
-
proof: IRateLimitProof | Uint8Array,
|
521
|
-
msg: Uint8Array,
|
522
|
-
...roots: Array<Uint8Array>
|
523
|
-
): boolean {
|
524
|
-
let pBytes: Uint8Array;
|
525
|
-
if (proof instanceof Uint8Array) {
|
526
|
-
pBytes = proof;
|
527
|
-
} else {
|
528
|
-
pBytes = proofToBytes(proof);
|
529
|
-
}
|
530
|
-
// calculate message length
|
531
|
-
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
532
|
-
|
533
|
-
const rootsBytes = concatenate(...roots);
|
534
|
-
|
535
|
-
return zerokitRLN.verifyWithRoots(
|
536
|
-
this.zkRLN,
|
537
|
-
concatenate(pBytes, msgLen, msg),
|
538
|
-
rootsBytes
|
539
|
-
);
|
540
|
-
}
|
541
|
-
|
542
|
-
verifyWithNoRoot(
|
543
|
-
proof: IRateLimitProof | Uint8Array,
|
544
|
-
msg: Uint8Array
|
545
|
-
): boolean {
|
546
|
-
let pBytes: Uint8Array;
|
547
|
-
if (proof instanceof Uint8Array) {
|
548
|
-
pBytes = proof;
|
549
|
-
} else {
|
550
|
-
pBytes = proofToBytes(proof);
|
551
|
-
}
|
552
|
-
|
553
|
-
// calculate message length
|
554
|
-
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
555
|
-
|
556
|
-
return zerokitRLN.verifyWithRoots(
|
557
|
-
this.zkRLN,
|
558
|
-
concatenate(pBytes, msgLen, msg),
|
559
|
-
new Uint8Array()
|
560
|
-
);
|
561
|
-
}
|
562
286
|
}
|
package/src/root_tracker.ts
CHANGED
package/src/zerokit.ts
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
import type { IRateLimitProof } from "@waku/interfaces";
|
2
|
+
import * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
3
|
+
|
4
|
+
import { IdentityCredential } from "./identity.js";
|
5
|
+
import { Proof, proofToBytes } from "./proof.js";
|
6
|
+
import { WitnessCalculator } from "./resources/witness_calculator.js";
|
7
|
+
import {
|
8
|
+
concatenate,
|
9
|
+
dateToEpoch,
|
10
|
+
epochIntToBytes,
|
11
|
+
writeUIntLE
|
12
|
+
} from "./utils/index.js";
|
13
|
+
|
14
|
+
export class Zerokit {
|
15
|
+
constructor(
|
16
|
+
private zkRLN: number,
|
17
|
+
private witnessCalculator: WitnessCalculator
|
18
|
+
) {}
|
19
|
+
|
20
|
+
generateIdentityCredentials(): IdentityCredential {
|
21
|
+
const memKeys = zerokitRLN.generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm
|
22
|
+
return IdentityCredential.fromBytes(memKeys);
|
23
|
+
}
|
24
|
+
|
25
|
+
generateSeededIdentityCredential(seed: string): IdentityCredential {
|
26
|
+
const stringEncoder = new TextEncoder();
|
27
|
+
const seedBytes = stringEncoder.encode(seed);
|
28
|
+
// TODO: rename this function in zerokit rln-wasm
|
29
|
+
const memKeys = zerokitRLN.generateSeededExtendedMembershipKey(
|
30
|
+
this.zkRLN,
|
31
|
+
seedBytes
|
32
|
+
);
|
33
|
+
return IdentityCredential.fromBytes(memKeys);
|
34
|
+
}
|
35
|
+
|
36
|
+
insertMember(idCommitment: Uint8Array): void {
|
37
|
+
zerokitRLN.insertMember(this.zkRLN, idCommitment);
|
38
|
+
}
|
39
|
+
|
40
|
+
insertMembers(index: number, ...idCommitments: Array<Uint8Array>): void {
|
41
|
+
// serializes a seq of IDCommitments to a byte seq
|
42
|
+
// the order of serialization is |id_commitment_len<8>|id_commitment<var>|
|
43
|
+
const idCommitmentLen = writeUIntLE(
|
44
|
+
new Uint8Array(8),
|
45
|
+
idCommitments.length,
|
46
|
+
0,
|
47
|
+
8
|
48
|
+
);
|
49
|
+
const idCommitmentBytes = concatenate(idCommitmentLen, ...idCommitments);
|
50
|
+
zerokitRLN.setLeavesFrom(this.zkRLN, index, idCommitmentBytes);
|
51
|
+
}
|
52
|
+
|
53
|
+
deleteMember(index: number): void {
|
54
|
+
zerokitRLN.deleteLeaf(this.zkRLN, index);
|
55
|
+
}
|
56
|
+
|
57
|
+
getMerkleRoot(): Uint8Array {
|
58
|
+
return zerokitRLN.getRoot(this.zkRLN);
|
59
|
+
}
|
60
|
+
|
61
|
+
serializeMessage(
|
62
|
+
uint8Msg: Uint8Array,
|
63
|
+
memIndex: number,
|
64
|
+
epoch: Uint8Array,
|
65
|
+
idKey: Uint8Array
|
66
|
+
): Uint8Array {
|
67
|
+
// calculate message length
|
68
|
+
const msgLen = writeUIntLE(new Uint8Array(8), uint8Msg.length, 0, 8);
|
69
|
+
|
70
|
+
// Converting index to LE bytes
|
71
|
+
const memIndexBytes = writeUIntLE(new Uint8Array(8), memIndex, 0, 8);
|
72
|
+
|
73
|
+
// [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
74
|
+
return concatenate(idKey, memIndexBytes, epoch, msgLen, uint8Msg);
|
75
|
+
}
|
76
|
+
|
77
|
+
async generateRLNProof(
|
78
|
+
msg: Uint8Array,
|
79
|
+
index: number,
|
80
|
+
epoch: Uint8Array | Date | undefined,
|
81
|
+
idSecretHash: Uint8Array
|
82
|
+
): Promise<IRateLimitProof> {
|
83
|
+
if (epoch == undefined) {
|
84
|
+
epoch = epochIntToBytes(dateToEpoch(new Date()));
|
85
|
+
} else if (epoch instanceof Date) {
|
86
|
+
epoch = epochIntToBytes(dateToEpoch(epoch));
|
87
|
+
}
|
88
|
+
|
89
|
+
if (epoch.length != 32) throw "invalid epoch";
|
90
|
+
if (idSecretHash.length != 32) throw "invalid id secret hash";
|
91
|
+
if (index < 0) throw "index must be >= 0";
|
92
|
+
|
93
|
+
const serialized_msg = this.serializeMessage(
|
94
|
+
msg,
|
95
|
+
index,
|
96
|
+
epoch,
|
97
|
+
idSecretHash
|
98
|
+
);
|
99
|
+
const rlnWitness = zerokitRLN.getSerializedRLNWitness(
|
100
|
+
this.zkRLN,
|
101
|
+
serialized_msg
|
102
|
+
);
|
103
|
+
const inputs = zerokitRLN.RLNWitnessToJson(this.zkRLN, rlnWitness);
|
104
|
+
const calculatedWitness = await this.witnessCalculator.calculateWitness(
|
105
|
+
inputs,
|
106
|
+
false
|
107
|
+
); // no sanity check being used in zerokit
|
108
|
+
|
109
|
+
const proofBytes = zerokitRLN.generate_rln_proof_with_witness(
|
110
|
+
this.zkRLN,
|
111
|
+
calculatedWitness,
|
112
|
+
rlnWitness
|
113
|
+
);
|
114
|
+
|
115
|
+
return new Proof(proofBytes);
|
116
|
+
}
|
117
|
+
|
118
|
+
verifyRLNProof(
|
119
|
+
proof: IRateLimitProof | Uint8Array,
|
120
|
+
msg: Uint8Array
|
121
|
+
): boolean {
|
122
|
+
let pBytes: Uint8Array;
|
123
|
+
if (proof instanceof Uint8Array) {
|
124
|
+
pBytes = proof;
|
125
|
+
} else {
|
126
|
+
pBytes = proofToBytes(proof);
|
127
|
+
}
|
128
|
+
|
129
|
+
// calculate message length
|
130
|
+
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
131
|
+
|
132
|
+
return zerokitRLN.verifyRLNProof(
|
133
|
+
this.zkRLN,
|
134
|
+
concatenate(pBytes, msgLen, msg)
|
135
|
+
);
|
136
|
+
}
|
137
|
+
|
138
|
+
verifyWithRoots(
|
139
|
+
proof: IRateLimitProof | Uint8Array,
|
140
|
+
msg: Uint8Array,
|
141
|
+
...roots: Array<Uint8Array>
|
142
|
+
): boolean {
|
143
|
+
let pBytes: Uint8Array;
|
144
|
+
if (proof instanceof Uint8Array) {
|
145
|
+
pBytes = proof;
|
146
|
+
} else {
|
147
|
+
pBytes = proofToBytes(proof);
|
148
|
+
}
|
149
|
+
// calculate message length
|
150
|
+
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
151
|
+
|
152
|
+
const rootsBytes = concatenate(...roots);
|
153
|
+
|
154
|
+
return zerokitRLN.verifyWithRoots(
|
155
|
+
this.zkRLN,
|
156
|
+
concatenate(pBytes, msgLen, msg),
|
157
|
+
rootsBytes
|
158
|
+
);
|
159
|
+
}
|
160
|
+
|
161
|
+
verifyWithNoRoot(
|
162
|
+
proof: IRateLimitProof | Uint8Array,
|
163
|
+
msg: Uint8Array
|
164
|
+
): boolean {
|
165
|
+
let pBytes: Uint8Array;
|
166
|
+
if (proof instanceof Uint8Array) {
|
167
|
+
pBytes = proof;
|
168
|
+
} else {
|
169
|
+
pBytes = proofToBytes(proof);
|
170
|
+
}
|
171
|
+
|
172
|
+
// calculate message length
|
173
|
+
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
174
|
+
|
175
|
+
return zerokitRLN.verifyWithRoots(
|
176
|
+
this.zkRLN,
|
177
|
+
concatenate(pBytes, msgLen, msg),
|
178
|
+
new Uint8Array()
|
179
|
+
);
|
180
|
+
}
|
181
|
+
}
|