@waku/rln 0.0.6 → 0.0.8-4b656ce

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,23 +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
 
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
- }
20
-
21
7
  /**
22
8
  * Concatenate Uint8Arrays
23
9
  * @param input
@@ -37,10 +23,21 @@ function concatenate(...input: Uint8Array[]): Uint8Array {
37
23
  return result;
38
24
  }
39
25
 
26
+ const stringEncoder = new TextEncoder();
27
+
40
28
  const DEPTH = 20;
41
- const VERIFICATION_KEY = base64ToUint8Array(resources.verification_key);
42
- const ZKEY = base64ToUint8Array(resources.zkey);
43
- const CIRCUIT = base64ToUint8Array(resources.circuit);
29
+
30
+ async function loadWitnessCalculator(): Promise<any> {
31
+ const url = new URL("./resources/rln.wasm", import.meta.url);
32
+ const response = await fetch(url);
33
+ return await wc.builder(new Uint8Array(await response.arrayBuffer()), false);
34
+ }
35
+
36
+ async function loadZkey(): Promise<Uint8Array> {
37
+ const url = new URL("./resources/rln_final.zkey", import.meta.url);
38
+ const response = await fetch(url);
39
+ return new Uint8Array(await response.arrayBuffer());
40
+ }
44
41
 
45
42
  /**
46
43
  * Create an instance of RLN
@@ -49,9 +46,10 @@ const CIRCUIT = base64ToUint8Array(resources.circuit);
49
46
  export async function create(): Promise<RLNInstance> {
50
47
  await init();
51
48
  zerokitRLN.init_panic_hook();
52
-
53
- const witnessCalculator = await wc.builder(CIRCUIT, false);
54
- const zkRLN = zerokitRLN.newRLN(DEPTH, ZKEY, VERIFICATION_KEY);
49
+ const witnessCalculator = await loadWitnessCalculator();
50
+ const zkey = await loadZkey();
51
+ const vkey = stringEncoder.encode(JSON.stringify(verificationKey));
52
+ const zkRLN = zerokitRLN.newRLN(DEPTH, zkey, vkey);
55
53
  return new RLNInstance(zkRLN, witnessCalculator);
56
54
  }
57
55
 
@@ -123,7 +121,7 @@ const shareYOffset = shareXOffset + 32;
123
121
  const nullifierOffset = shareYOffset + 32;
124
122
  const rlnIdentifierOffset = nullifierOffset + 32;
125
123
 
126
- export class RateLimitProof {
124
+ export class Proof implements RateLimitProof {
127
125
  readonly proof: Uint8Array;
128
126
  readonly merkleRoot: Uint8Array;
129
127
  readonly epoch: Uint8Array;
@@ -146,18 +144,18 @@ export class RateLimitProof {
146
144
  rlnIdentifierOffset
147
145
  );
148
146
  }
147
+ }
149
148
 
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
- }
149
+ function proofToBytes(p: RateLimitProof): Uint8Array {
150
+ return concatenate(
151
+ p.proof,
152
+ p.merkleRoot,
153
+ p.epoch,
154
+ p.shareX,
155
+ p.shareY,
156
+ p.nullifier,
157
+ p.rlnIdentifier
158
+ );
161
159
  }
162
160
 
163
161
  export class RLNInstance {
@@ -221,13 +219,16 @@ export class RLNInstance {
221
219
  rlnWitness
222
220
  );
223
221
 
224
- return new RateLimitProof(proofBytes);
222
+ return new Proof(proofBytes);
225
223
  }
226
224
 
227
225
  verifyProof(proof: RateLimitProof | Uint8Array): boolean {
228
- if (proof instanceof RateLimitProof) {
229
- proof = proof.toBytes();
226
+ let pBytes: Uint8Array;
227
+ if (proof instanceof Uint8Array) {
228
+ pBytes = proof;
229
+ } else {
230
+ pBytes = proofToBytes(proof);
230
231
  }
231
- return zerokitRLN.verifyProof(this.zkRLN, proof);
232
+ return zerokitRLN.verifyProof(this.zkRLN, pBytes);
232
233
  }
233
234
  }