@waku/rln 0.0.6 → 0.0.8-38fdb53

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/src/encoder.ts ADDED
@@ -0,0 +1,81 @@
1
+ import debug from "debug";
2
+ import { proto_message, utils } from "js-waku";
3
+ import {
4
+ Decoder,
5
+ Encoder,
6
+ Message,
7
+ ProtoMessage,
8
+ } from "js-waku/lib/interfaces";
9
+
10
+ import { MembershipKey, RLNInstance } from "./rln.js";
11
+
12
+ const log = debug("waku:message:rln-encoder");
13
+
14
+ export class RLNEncoder implements Encoder {
15
+ public contentTopic: string;
16
+ private readonly idKey: Uint8Array;
17
+
18
+ constructor(
19
+ private encoder: Encoder,
20
+ private rlnInstance: RLNInstance,
21
+ private index: number,
22
+ membershipKey: MembershipKey
23
+ ) {
24
+ if (index < 0) throw "invalid membership index";
25
+ this.idKey = membershipKey.IDKey;
26
+ this.contentTopic = encoder.contentTopic;
27
+ }
28
+
29
+ async encode(message: Message): Promise<Uint8Array | undefined> {
30
+ const protoMessage = await this.encodeProto(message);
31
+ if (!protoMessage) return;
32
+ return proto_message.WakuMessage.encode(protoMessage);
33
+ }
34
+
35
+ async encodeProto(message: Message): Promise<ProtoMessage | undefined> {
36
+ const protoMessage = await this.encoder.encodeProto(message);
37
+ if (!protoMessage) return;
38
+
39
+ const signal = toRLNSignal(message);
40
+
41
+ console.time("proof_gen_timer");
42
+ const proof = await this.rlnInstance.generateProof(
43
+ signal,
44
+ this.index,
45
+ message.timestamp,
46
+ this.idKey
47
+ );
48
+ console.timeEnd("proof_gen_timer");
49
+
50
+ protoMessage.rateLimitProof = proof;
51
+
52
+ return protoMessage;
53
+ }
54
+ }
55
+
56
+ export class RLNDecoder implements Decoder<Message> {
57
+ public contentTopic: string;
58
+
59
+ constructor(private decoder: Decoder<Message>) {
60
+ this.contentTopic = decoder.contentTopic;
61
+ }
62
+
63
+ decodeProto(bytes: Uint8Array): Promise<ProtoMessage | undefined> {
64
+ const protoMessage = proto_message.WakuMessage.decode(bytes);
65
+ log("Message decoded", protoMessage);
66
+ return Promise.resolve(protoMessage);
67
+ }
68
+
69
+ async decode(proto: ProtoMessage): Promise<Message | undefined> {
70
+ const msg = await this.decoder.decode(proto);
71
+ if (msg) {
72
+ msg.rateLimitProof = proto.rateLimitProof;
73
+ }
74
+ return msg;
75
+ }
76
+ }
77
+
78
+ function toRLNSignal(msg: Message): Uint8Array {
79
+ const contentTopicBytes = utils.utf8ToBytes(msg.contentTopic ?? "");
80
+ return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
81
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MembershipKey, RateLimitProof, RLNInstance } from "./rln.js";
1
+ import type { MembershipKey, Proof, RLNInstance } from "./rln.js";
2
2
 
3
3
  // reexport the create function, dynamically imported from rln.ts
4
4
  export async function create(): Promise<RLNInstance> {
@@ -9,4 +9,4 @@ export async function create(): Promise<RLNInstance> {
9
9
  return await rlnModule.create();
10
10
  }
11
11
 
12
- export { RLNInstance, MembershipKey, RateLimitProof };
12
+ export { RLNInstance, MembershipKey, Proof };
package/src/rln.ts CHANGED
@@ -1,22 +1,9 @@
1
1
  import init, * as zerokitRLN from "@waku/zerokit-rln-wasm";
2
+ import { RateLimitProof } from "js-waku/lib/interfaces";
2
3
 
3
- import * as resources from "./resources.js";
4
+ import verificationKey from "./resources/verification_key.js";
4
5
  import * as wc from "./witness_calculator.js";
5
-
6
- /**
7
- * Convert a base64 string into uint8Array
8
- * @param base64
9
- * @returns Uint8Array
10
- */
11
- function base64ToUint8Array(base64: string): Uint8Array {
12
- const binary_string = window.atob(base64);
13
- const len = binary_string.length;
14
- const bytes = new Uint8Array(len);
15
- for (let i = 0; i < len; i++) {
16
- bytes[i] = binary_string.charCodeAt(i);
17
- }
18
- return bytes;
19
- }
6
+ import { WitnessCalculator } from "./witness_calculator.js";
20
7
 
21
8
  /**
22
9
  * Concatenate Uint8Arrays
@@ -37,10 +24,21 @@ function concatenate(...input: Uint8Array[]): Uint8Array {
37
24
  return result;
38
25
  }
39
26
 
27
+ const stringEncoder = new TextEncoder();
28
+
40
29
  const DEPTH = 20;
41
- const VERIFICATION_KEY = base64ToUint8Array(resources.verification_key);
42
- const ZKEY = base64ToUint8Array(resources.zkey);
43
- const CIRCUIT = base64ToUint8Array(resources.circuit);
30
+
31
+ async function loadWitnessCalculator(): Promise<WitnessCalculator> {
32
+ const url = new URL("./resources/rln.wasm", import.meta.url);
33
+ const response = await fetch(url);
34
+ return await wc.builder(new Uint8Array(await response.arrayBuffer()), false);
35
+ }
36
+
37
+ async function loadZkey(): Promise<Uint8Array> {
38
+ const url = new URL("./resources/rln_final.zkey", import.meta.url);
39
+ const response = await fetch(url);
40
+ return new Uint8Array(await response.arrayBuffer());
41
+ }
44
42
 
45
43
  /**
46
44
  * Create an instance of RLN
@@ -49,19 +47,23 @@ const CIRCUIT = base64ToUint8Array(resources.circuit);
49
47
  export async function create(): Promise<RLNInstance> {
50
48
  await init();
51
49
  zerokitRLN.init_panic_hook();
52
-
53
- const witnessCalculator = await wc.builder(CIRCUIT, false);
54
- const zkRLN = zerokitRLN.newRLN(DEPTH, ZKEY, VERIFICATION_KEY);
50
+ const witnessCalculator = await loadWitnessCalculator();
51
+ const zkey = await loadZkey();
52
+ const vkey = stringEncoder.encode(JSON.stringify(verificationKey));
53
+ const zkRLN = zerokitRLN.newRLN(DEPTH, zkey, vkey);
55
54
  return new RLNInstance(zkRLN, witnessCalculator);
56
55
  }
57
56
 
58
57
  export class MembershipKey {
59
- readonly IDKey: Uint8Array;
60
- readonly IDCommitment: Uint8Array;
61
-
62
- constructor(memKeys: Uint8Array) {
63
- this.IDKey = memKeys.subarray(0, 32);
64
- this.IDCommitment = memKeys.subarray(32);
58
+ constructor(
59
+ public readonly IDKey: Uint8Array,
60
+ public readonly IDCommitment: Uint8Array
61
+ ) {}
62
+
63
+ static fromBytes(memKeys: Uint8Array): MembershipKey {
64
+ const idKey = memKeys.subarray(0, 32);
65
+ const idCommitment = memKeys.subarray(32);
66
+ return new MembershipKey(idKey, idCommitment);
65
67
  }
66
68
  }
67
69
 
@@ -123,7 +125,7 @@ const shareYOffset = shareXOffset + 32;
123
125
  const nullifierOffset = shareYOffset + 32;
124
126
  const rlnIdentifierOffset = nullifierOffset + 32;
125
127
 
126
- export class RateLimitProof {
128
+ export class Proof implements RateLimitProof {
127
129
  readonly proof: Uint8Array;
128
130
  readonly merkleRoot: Uint8Array;
129
131
  readonly epoch: Uint8Array;
@@ -146,26 +148,29 @@ export class RateLimitProof {
146
148
  rlnIdentifierOffset
147
149
  );
148
150
  }
151
+ }
149
152
 
150
- toBytes(): Uint8Array {
151
- return concatenate(
152
- this.proof,
153
- this.merkleRoot,
154
- this.epoch,
155
- this.shareX,
156
- this.shareY,
157
- this.nullifier,
158
- this.rlnIdentifier
159
- );
160
- }
153
+ function proofToBytes(p: RateLimitProof): Uint8Array {
154
+ return concatenate(
155
+ p.proof,
156
+ p.merkleRoot,
157
+ p.epoch,
158
+ p.shareX,
159
+ p.shareY,
160
+ p.nullifier,
161
+ p.rlnIdentifier
162
+ );
161
163
  }
162
164
 
163
165
  export class RLNInstance {
164
- constructor(private zkRLN: number, private witnessCalculator: any) {}
166
+ constructor(
167
+ private zkRLN: number,
168
+ private witnessCalculator: WitnessCalculator
169
+ ) {}
165
170
 
166
171
  generateMembershipKey(): MembershipKey {
167
172
  const memKeys = zerokitRLN.generateMembershipKey(this.zkRLN);
168
- return new MembershipKey(memKeys);
173
+ return MembershipKey.fromBytes(memKeys);
169
174
  }
170
175
 
171
176
  insertMember(idCommitment: Uint8Array): void {
@@ -221,13 +226,16 @@ export class RLNInstance {
221
226
  rlnWitness
222
227
  );
223
228
 
224
- return new RateLimitProof(proofBytes);
229
+ return new Proof(proofBytes);
225
230
  }
226
231
 
227
232
  verifyProof(proof: RateLimitProof | Uint8Array): boolean {
228
- if (proof instanceof RateLimitProof) {
229
- proof = proof.toBytes();
233
+ let pBytes: Uint8Array;
234
+ if (proof instanceof Uint8Array) {
235
+ pBytes = proof;
236
+ } else {
237
+ pBytes = proofToBytes(proof);
230
238
  }
231
- return zerokitRLN.verifyProof(this.zkRLN, proof);
239
+ return zerokitRLN.verifyProof(this.zkRLN, pBytes);
232
240
  }
233
241
  }
@@ -1,4 +1,8 @@
1
1
  export async function builder(
2
2
  code: Uint8Array,
3
3
  sanityCheck: bool
4
- ): Promise<any>;
4
+ ): Promise<WitnessCalculator>;
5
+
6
+ export class WitnessCalculator {
7
+ calculateWitness(input, sanityCheck): Array<bigint>;
8
+ }