@waku/rln 0.0.7 → 0.0.8-378ad04
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 +47343 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/byte_utils.d.ts +1 -0
- package/dist/byte_utils.js +24 -0
- package/dist/byte_utils.js.map +1 -0
- package/dist/codec.d.ts +22 -0
- package/dist/codec.js +58 -0
- package/dist/codec.js.map +1 -0
- package/dist/epoch.d.ts +3 -0
- package/dist/epoch.js +16 -0
- package/dist/epoch.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/message.d.ts +13 -0
- package/dist/message.js +29 -0
- package/dist/message.js.map +1 -0
- package/dist/resources/verification_key.d.ts +12 -0
- package/dist/resources/verification_key.js +121 -0
- package/dist/resources/verification_key.js.map +1 -0
- package/dist/rln.d.ts +6 -5
- package/dist/rln.js +25 -42
- package/dist/rln.js.map +1 -1
- package/package.json +4 -3
- package/src/byte_utils.ts +39 -0
- package/src/codec.ts +88 -0
- package/src/epoch.ts +21 -0
- package/src/index.ts +4 -2
- package/src/message.ts +37 -0
- package/src/rln.ts +41 -78
- package/src/witness_calculator.d.ts +5 -1
- package/bundle/rln-4592cf99.js +0 -1147
package/dist/rln.js
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import init, * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
2
|
-
import
|
2
|
+
import { writeUIntLE } from "./byte_utils.js";
|
3
|
+
import { dateToEpoch, epochIntToBytes } from "./epoch.js";
|
4
|
+
import verificationKey from "./resources/verification_key.js";
|
3
5
|
import * as wc from "./witness_calculator.js";
|
4
6
|
/**
|
5
7
|
* Concatenate Uint8Arrays
|
@@ -45,38 +47,15 @@ export async function create() {
|
|
45
47
|
return new RLNInstance(zkRLN, witnessCalculator);
|
46
48
|
}
|
47
49
|
export class MembershipKey {
|
48
|
-
constructor(
|
49
|
-
this.IDKey =
|
50
|
-
this.IDCommitment =
|
50
|
+
constructor(IDKey, IDCommitment) {
|
51
|
+
this.IDKey = IDKey;
|
52
|
+
this.IDCommitment = IDCommitment;
|
51
53
|
}
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
throw new RangeError('"value" argument is out of bounds');
|
57
|
-
if (offset + ext > buf.length)
|
58
|
-
throw new RangeError("Index out of range");
|
59
|
-
}
|
60
|
-
const writeUIntLE = function writeUIntLE(buf, value, offset, byteLength, noAssert) {
|
61
|
-
value = +value;
|
62
|
-
offset = offset >>> 0;
|
63
|
-
byteLength = byteLength >>> 0;
|
64
|
-
if (!noAssert) {
|
65
|
-
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
66
|
-
checkInt(buf, value, offset, byteLength, maxBytes, 0);
|
67
|
-
}
|
68
|
-
let mul = 1;
|
69
|
-
let i = 0;
|
70
|
-
buf[offset] = value & 0xff;
|
71
|
-
while (++i < byteLength && (mul *= 0x100)) {
|
72
|
-
buf[offset + i] = (value / mul) & 0xff;
|
54
|
+
static fromBytes(memKeys) {
|
55
|
+
const idKey = memKeys.subarray(0, 32);
|
56
|
+
const idCommitment = memKeys.subarray(32);
|
57
|
+
return new MembershipKey(idKey, idCommitment);
|
73
58
|
}
|
74
|
-
return buf;
|
75
|
-
};
|
76
|
-
const DefaultEpochUnitSeconds = 10; // the rln-relay epoch length in seconds
|
77
|
-
export function toEpoch(timestamp, epochUnitSeconds = DefaultEpochUnitSeconds) {
|
78
|
-
const unix = Math.floor(timestamp.getTime() / 1000 / epochUnitSeconds);
|
79
|
-
return writeUIntLE(new Uint8Array(32), unix, 0, 8);
|
80
59
|
}
|
81
60
|
const proofOffset = 128;
|
82
61
|
const rootOffset = proofOffset + 32;
|
@@ -85,7 +64,7 @@ const shareXOffset = epochOffset + 32;
|
|
85
64
|
const shareYOffset = shareXOffset + 32;
|
86
65
|
const nullifierOffset = shareYOffset + 32;
|
87
66
|
const rlnIdentifierOffset = nullifierOffset + 32;
|
88
|
-
export class
|
67
|
+
export class Proof {
|
89
68
|
constructor(proofBytes) {
|
90
69
|
if (proofBytes.length < rlnIdentifierOffset)
|
91
70
|
throw "invalid proof";
|
@@ -98,9 +77,9 @@ export class RateLimitProof {
|
|
98
77
|
this.nullifier = proofBytes.subarray(shareYOffset, nullifierOffset);
|
99
78
|
this.rlnIdentifier = proofBytes.subarray(nullifierOffset, rlnIdentifierOffset);
|
100
79
|
}
|
101
|
-
|
102
|
-
|
103
|
-
|
80
|
+
}
|
81
|
+
function proofToBytes(p) {
|
82
|
+
return concatenate(p.proof, p.merkleRoot, p.epoch, p.shareX, p.shareY, p.nullifier, p.rlnIdentifier);
|
104
83
|
}
|
105
84
|
export class RLNInstance {
|
106
85
|
constructor(zkRLN, witnessCalculator) {
|
@@ -109,7 +88,7 @@ export class RLNInstance {
|
|
109
88
|
}
|
110
89
|
generateMembershipKey() {
|
111
90
|
const memKeys = zerokitRLN.generateMembershipKey(this.zkRLN);
|
112
|
-
return
|
91
|
+
return MembershipKey.fromBytes(memKeys);
|
113
92
|
}
|
114
93
|
insertMember(idCommitment) {
|
115
94
|
zerokitRLN.insertMember(this.zkRLN, idCommitment);
|
@@ -124,10 +103,10 @@ export class RLNInstance {
|
|
124
103
|
}
|
125
104
|
async generateProof(msg, index, epoch, idKey) {
|
126
105
|
if (epoch == undefined) {
|
127
|
-
epoch =
|
106
|
+
epoch = epochIntToBytes(dateToEpoch(new Date()));
|
128
107
|
}
|
129
108
|
else if (epoch instanceof Date) {
|
130
|
-
epoch =
|
109
|
+
epoch = epochIntToBytes(dateToEpoch(epoch));
|
131
110
|
}
|
132
111
|
if (epoch.length != 32)
|
133
112
|
throw "invalid epoch";
|
@@ -140,13 +119,17 @@ export class RLNInstance {
|
|
140
119
|
const inputs = zerokitRLN.RLNWitnessToJson(this.zkRLN, rlnWitness);
|
141
120
|
const calculatedWitness = await this.witnessCalculator.calculateWitness(inputs, false); // no sanity check being used in zerokit
|
142
121
|
const proofBytes = zerokitRLN.generate_rln_proof_with_witness(this.zkRLN, calculatedWitness, rlnWitness);
|
143
|
-
return new
|
122
|
+
return new Proof(proofBytes);
|
144
123
|
}
|
145
124
|
verifyProof(proof) {
|
146
|
-
|
147
|
-
|
125
|
+
let pBytes;
|
126
|
+
if (proof instanceof Uint8Array) {
|
127
|
+
pBytes = proof;
|
128
|
+
}
|
129
|
+
else {
|
130
|
+
pBytes = proofToBytes(proof);
|
148
131
|
}
|
149
|
-
return zerokitRLN.verifyProof(this.zkRLN,
|
132
|
+
return zerokitRLN.verifyProof(this.zkRLN, pBytes);
|
150
133
|
}
|
151
134
|
}
|
152
135
|
//# sourceMappingURL=rln.js.map
|
package/dist/rln.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"rln.js","sourceRoot":"","sources":["../src/rln.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,KAAK,UAAU,MAAM,wBAAwB,CAAC;
|
1
|
+
{"version":3,"file":"rln.js","sourceRoot":"","sources":["../src/rln.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@waku/rln",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.8-378ad04",
|
4
4
|
"description": "Rate Limit Nullifier for js-waku",
|
5
5
|
"types": "./dist/index.d.ts",
|
6
6
|
"module": "./dist/index.js",
|
@@ -34,7 +34,7 @@
|
|
34
34
|
"test:lint": "eslint src --ext .ts",
|
35
35
|
"test:prettier": "prettier \"src/**/*.ts\" \"./*.json\" \"*.*js\" \".github/**/*.yml\" --list-different",
|
36
36
|
"test:spelling": "cspell \"{*.md,.github/*.md,src/**/*.ts}\"",
|
37
|
-
"test:tsc": "tsc",
|
37
|
+
"test:tsc": "tsc -p tsconfig.dev.json",
|
38
38
|
"test:browser": "karma start karma.conf.cjs",
|
39
39
|
"watch:build": "tsc -p tsconfig.json -w",
|
40
40
|
"watch:test": "mocha --watch",
|
@@ -76,11 +76,12 @@
|
|
76
76
|
"eslint-plugin-functional": "^4.0.2",
|
77
77
|
"eslint-plugin-import": "^2.25.3",
|
78
78
|
"eslint-plugin-prettier": "^4.0.0",
|
79
|
-
"fast-check": "^2.
|
79
|
+
"fast-check": "^2.25.0",
|
80
80
|
"gh-pages": "^3.2.3",
|
81
81
|
"husky": "^7.0.4",
|
82
82
|
"ignore-loader": "^0.1.2",
|
83
83
|
"isomorphic-fetch": "^3.0.0",
|
84
|
+
"js-waku": "^0.29.0-29436ea",
|
84
85
|
"jsdom": "^19.0.0",
|
85
86
|
"jsdom-global": "^3.0.2",
|
86
87
|
"karma": "^6.3.12",
|
@@ -0,0 +1,39 @@
|
|
1
|
+
// Adapted from https://github.com/feross/buffer
|
2
|
+
|
3
|
+
function checkInt(
|
4
|
+
buf: Uint8Array,
|
5
|
+
value: number,
|
6
|
+
offset: number,
|
7
|
+
ext: number,
|
8
|
+
max: number,
|
9
|
+
min: number
|
10
|
+
): void {
|
11
|
+
if (value > max || value < min)
|
12
|
+
throw new RangeError('"value" argument is out of bounds');
|
13
|
+
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
14
|
+
}
|
15
|
+
|
16
|
+
export function writeUIntLE(
|
17
|
+
buf: Uint8Array,
|
18
|
+
value: number,
|
19
|
+
offset: number,
|
20
|
+
byteLength: number,
|
21
|
+
noAssert?: boolean
|
22
|
+
): Uint8Array {
|
23
|
+
value = +value;
|
24
|
+
offset = offset >>> 0;
|
25
|
+
byteLength = byteLength >>> 0;
|
26
|
+
if (!noAssert) {
|
27
|
+
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
28
|
+
checkInt(buf, value, offset, byteLength, maxBytes, 0);
|
29
|
+
}
|
30
|
+
|
31
|
+
let mul = 1;
|
32
|
+
let i = 0;
|
33
|
+
buf[offset] = value & 0xff;
|
34
|
+
while (++i < byteLength && (mul *= 0x100)) {
|
35
|
+
buf[offset + i] = (value / mul) & 0xff;
|
36
|
+
}
|
37
|
+
|
38
|
+
return buf;
|
39
|
+
}
|
package/src/codec.ts
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
import debug from "debug";
|
2
|
+
import { utils } from "js-waku";
|
3
|
+
import {
|
4
|
+
Decoder,
|
5
|
+
Encoder,
|
6
|
+
Message,
|
7
|
+
ProtoMessage,
|
8
|
+
RateLimitProof,
|
9
|
+
} from "js-waku/lib/interfaces";
|
10
|
+
|
11
|
+
import { RlnMessage } from "./message.js";
|
12
|
+
import { MembershipKey, RLNInstance } from "./rln.js";
|
13
|
+
|
14
|
+
const log = debug("waku:message:rln-encoder");
|
15
|
+
|
16
|
+
export class RLNEncoder implements Encoder {
|
17
|
+
public contentTopic: string;
|
18
|
+
private readonly idKey: Uint8Array;
|
19
|
+
|
20
|
+
constructor(
|
21
|
+
private encoder: Encoder,
|
22
|
+
private rlnInstance: RLNInstance,
|
23
|
+
private index: number,
|
24
|
+
membershipKey: MembershipKey
|
25
|
+
) {
|
26
|
+
if (index < 0) throw "invalid membership index";
|
27
|
+
this.idKey = membershipKey.IDKey;
|
28
|
+
this.contentTopic = encoder.contentTopic;
|
29
|
+
}
|
30
|
+
|
31
|
+
async toWire(message: Partial<Message>): Promise<Uint8Array | undefined> {
|
32
|
+
message.rateLimitProof = await this.generateProof(message);
|
33
|
+
|
34
|
+
return this.encoder.toWire(message);
|
35
|
+
}
|
36
|
+
|
37
|
+
async toProtoObj(
|
38
|
+
message: Partial<Message>
|
39
|
+
): Promise<ProtoMessage | undefined> {
|
40
|
+
const protoMessage = await this.encoder.toProtoObj(message);
|
41
|
+
if (!protoMessage) return;
|
42
|
+
|
43
|
+
protoMessage.rateLimitProof = await this.generateProof(message);
|
44
|
+
|
45
|
+
return protoMessage;
|
46
|
+
}
|
47
|
+
|
48
|
+
private async generateProof(
|
49
|
+
message: Partial<Message>
|
50
|
+
): Promise<RateLimitProof> {
|
51
|
+
const signal = toRLNSignal(message);
|
52
|
+
|
53
|
+
console.time("proof_gen_timer");
|
54
|
+
const proof = await this.rlnInstance.generateProof(
|
55
|
+
signal,
|
56
|
+
this.index,
|
57
|
+
message.timestamp,
|
58
|
+
this.idKey
|
59
|
+
);
|
60
|
+
console.timeEnd("proof_gen_timer");
|
61
|
+
return proof;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
export class RLNDecoder<T extends Message> implements Decoder<RlnMessage<T>> {
|
66
|
+
constructor(private rlnInstance: RLNInstance, private decoder: Decoder<T>) {}
|
67
|
+
|
68
|
+
get contentTopic(): string {
|
69
|
+
return this.decoder.contentTopic;
|
70
|
+
}
|
71
|
+
|
72
|
+
fromWireToProtoObj(bytes: Uint8Array): Promise<ProtoMessage | undefined> {
|
73
|
+
const protoMessage = this.decoder.fromWireToProtoObj(bytes);
|
74
|
+
log("Message decoded", protoMessage);
|
75
|
+
return Promise.resolve(protoMessage);
|
76
|
+
}
|
77
|
+
|
78
|
+
async fromProtoObj(proto: ProtoMessage): Promise<RlnMessage<T> | undefined> {
|
79
|
+
const msg: T | undefined = await this.decoder.fromProtoObj(proto);
|
80
|
+
if (!msg) return;
|
81
|
+
return new RlnMessage(this.rlnInstance, msg, proto.rateLimitProof);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
function toRLNSignal(msg: Partial<Message>): Uint8Array {
|
86
|
+
const contentTopicBytes = utils.utf8ToBytes(msg.contentTopic ?? "");
|
87
|
+
return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
|
88
|
+
}
|
package/src/epoch.ts
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
const DefaultEpochUnitSeconds = 10; // the rln-relay epoch length in seconds
|
2
|
+
|
3
|
+
export function dateToEpoch(
|
4
|
+
timestamp: Date,
|
5
|
+
epochUnitSeconds: number = DefaultEpochUnitSeconds
|
6
|
+
): number {
|
7
|
+
const time = timestamp.getTime();
|
8
|
+
return Math.floor(time / 1000 / epochUnitSeconds);
|
9
|
+
}
|
10
|
+
|
11
|
+
export function epochIntToBytes(epoch: number): Uint8Array {
|
12
|
+
const bytes = new Uint8Array(32);
|
13
|
+
const db = new DataView(bytes.buffer);
|
14
|
+
db.setUint32(0, epoch, true);
|
15
|
+
return bytes;
|
16
|
+
}
|
17
|
+
|
18
|
+
export function epochBytesToInt(bytes: Uint8Array): number {
|
19
|
+
const dv = new DataView(bytes.buffer);
|
20
|
+
return dv.getUint32(0, true);
|
21
|
+
}
|
package/src/index.ts
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
import
|
1
|
+
import { RLNDecoder, RLNEncoder } from "./codec.js";
|
2
|
+
import type { Proof, RLNInstance } from "./rln.js";
|
3
|
+
import { MembershipKey } from "./rln.js";
|
2
4
|
|
3
5
|
// reexport the create function, dynamically imported from rln.ts
|
4
6
|
export async function create(): Promise<RLNInstance> {
|
@@ -9,4 +11,4 @@ export async function create(): Promise<RLNInstance> {
|
|
9
11
|
return await rlnModule.create();
|
10
12
|
}
|
11
13
|
|
12
|
-
export { RLNInstance, MembershipKey,
|
14
|
+
export { RLNInstance, MembershipKey, Proof, RLNEncoder, RLNDecoder };
|
package/src/message.ts
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
import { Message, RateLimitProof } from "js-waku/lib/interfaces";
|
2
|
+
|
3
|
+
import { epochBytesToInt } from "./epoch.js";
|
4
|
+
import { RLNInstance } from "./rln.js";
|
5
|
+
|
6
|
+
export class RlnMessage<T extends Message> implements Message {
|
7
|
+
constructor(
|
8
|
+
public rlnInstance: RLNInstance,
|
9
|
+
public msg: T,
|
10
|
+
public rateLimitProof: RateLimitProof | undefined
|
11
|
+
) {}
|
12
|
+
|
13
|
+
public verify(): boolean | undefined {
|
14
|
+
return this.rateLimitProof
|
15
|
+
? this.rlnInstance.verifyProof(this.rateLimitProof)
|
16
|
+
: undefined;
|
17
|
+
}
|
18
|
+
|
19
|
+
get payload(): Uint8Array | undefined {
|
20
|
+
return this.msg.payload;
|
21
|
+
}
|
22
|
+
|
23
|
+
get contentTopic(): string | undefined {
|
24
|
+
return this.msg.contentTopic;
|
25
|
+
}
|
26
|
+
|
27
|
+
get timestamp(): Date | undefined {
|
28
|
+
return this.msg.timestamp;
|
29
|
+
}
|
30
|
+
|
31
|
+
get epoch(): number | undefined {
|
32
|
+
const bytes = this.msg.rateLimitProof?.epoch;
|
33
|
+
if (!bytes) return;
|
34
|
+
|
35
|
+
return epochBytesToInt(bytes);
|
36
|
+
}
|
37
|
+
}
|
package/src/rln.ts
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
import init, * as zerokitRLN from "@waku/zerokit-rln-wasm";
|
2
|
+
import { RateLimitProof } from "js-waku/lib/interfaces";
|
2
3
|
|
3
|
-
import
|
4
|
+
import { writeUIntLE } from "./byte_utils.js";
|
5
|
+
import { dateToEpoch, epochIntToBytes } from "./epoch.js";
|
6
|
+
import verificationKey from "./resources/verification_key.js";
|
4
7
|
import * as wc from "./witness_calculator.js";
|
8
|
+
import { WitnessCalculator } from "./witness_calculator.js";
|
5
9
|
|
6
10
|
/**
|
7
11
|
* Concatenate Uint8Arrays
|
@@ -26,7 +30,7 @@ const stringEncoder = new TextEncoder();
|
|
26
30
|
|
27
31
|
const DEPTH = 20;
|
28
32
|
|
29
|
-
async function loadWitnessCalculator(): Promise<
|
33
|
+
async function loadWitnessCalculator(): Promise<WitnessCalculator> {
|
30
34
|
const url = new URL("./resources/rln.wasm", import.meta.url);
|
31
35
|
const response = await fetch(url);
|
32
36
|
return await wc.builder(new Uint8Array(await response.arrayBuffer()), false);
|
@@ -53,63 +57,16 @@ export async function create(): Promise<RLNInstance> {
|
|
53
57
|
}
|
54
58
|
|
55
59
|
export class MembershipKey {
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
// Adapted from https://github.com/feross/buffer
|
66
|
-
|
67
|
-
function checkInt(
|
68
|
-
buf: Uint8Array,
|
69
|
-
value: number,
|
70
|
-
offset: number,
|
71
|
-
ext: number,
|
72
|
-
max: number,
|
73
|
-
min: number
|
74
|
-
): void {
|
75
|
-
if (value > max || value < min)
|
76
|
-
throw new RangeError('"value" argument is out of bounds');
|
77
|
-
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
78
|
-
}
|
79
|
-
|
80
|
-
const writeUIntLE = function writeUIntLE(
|
81
|
-
buf: Uint8Array,
|
82
|
-
value: number,
|
83
|
-
offset: number,
|
84
|
-
byteLength: number,
|
85
|
-
noAssert?: boolean
|
86
|
-
): Uint8Array {
|
87
|
-
value = +value;
|
88
|
-
offset = offset >>> 0;
|
89
|
-
byteLength = byteLength >>> 0;
|
90
|
-
if (!noAssert) {
|
91
|
-
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
92
|
-
checkInt(buf, value, offset, byteLength, maxBytes, 0);
|
93
|
-
}
|
94
|
-
|
95
|
-
let mul = 1;
|
96
|
-
let i = 0;
|
97
|
-
buf[offset] = value & 0xff;
|
98
|
-
while (++i < byteLength && (mul *= 0x100)) {
|
99
|
-
buf[offset + i] = (value / mul) & 0xff;
|
60
|
+
constructor(
|
61
|
+
public readonly IDKey: Uint8Array,
|
62
|
+
public readonly IDCommitment: Uint8Array
|
63
|
+
) {}
|
64
|
+
|
65
|
+
static fromBytes(memKeys: Uint8Array): MembershipKey {
|
66
|
+
const idKey = memKeys.subarray(0, 32);
|
67
|
+
const idCommitment = memKeys.subarray(32);
|
68
|
+
return new MembershipKey(idKey, idCommitment);
|
100
69
|
}
|
101
|
-
|
102
|
-
return buf;
|
103
|
-
};
|
104
|
-
|
105
|
-
const DefaultEpochUnitSeconds = 10; // the rln-relay epoch length in seconds
|
106
|
-
|
107
|
-
export function toEpoch(
|
108
|
-
timestamp: Date,
|
109
|
-
epochUnitSeconds: number = DefaultEpochUnitSeconds
|
110
|
-
): Uint8Array {
|
111
|
-
const unix = Math.floor(timestamp.getTime() / 1000 / epochUnitSeconds);
|
112
|
-
return writeUIntLE(new Uint8Array(32), unix, 0, 8);
|
113
70
|
}
|
114
71
|
|
115
72
|
const proofOffset = 128;
|
@@ -120,7 +77,7 @@ const shareYOffset = shareXOffset + 32;
|
|
120
77
|
const nullifierOffset = shareYOffset + 32;
|
121
78
|
const rlnIdentifierOffset = nullifierOffset + 32;
|
122
79
|
|
123
|
-
export class RateLimitProof {
|
80
|
+
export class Proof implements RateLimitProof {
|
124
81
|
readonly proof: Uint8Array;
|
125
82
|
readonly merkleRoot: Uint8Array;
|
126
83
|
readonly epoch: Uint8Array;
|
@@ -143,26 +100,29 @@ export class RateLimitProof {
|
|
143
100
|
rlnIdentifierOffset
|
144
101
|
);
|
145
102
|
}
|
103
|
+
}
|
146
104
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
}
|
105
|
+
function proofToBytes(p: RateLimitProof): Uint8Array {
|
106
|
+
return concatenate(
|
107
|
+
p.proof,
|
108
|
+
p.merkleRoot,
|
109
|
+
p.epoch,
|
110
|
+
p.shareX,
|
111
|
+
p.shareY,
|
112
|
+
p.nullifier,
|
113
|
+
p.rlnIdentifier
|
114
|
+
);
|
158
115
|
}
|
159
116
|
|
160
117
|
export class RLNInstance {
|
161
|
-
constructor(
|
118
|
+
constructor(
|
119
|
+
private zkRLN: number,
|
120
|
+
private witnessCalculator: WitnessCalculator
|
121
|
+
) {}
|
162
122
|
|
163
123
|
generateMembershipKey(): MembershipKey {
|
164
124
|
const memKeys = zerokitRLN.generateMembershipKey(this.zkRLN);
|
165
|
-
return
|
125
|
+
return MembershipKey.fromBytes(memKeys);
|
166
126
|
}
|
167
127
|
|
168
128
|
insertMember(idCommitment: Uint8Array): void {
|
@@ -192,9 +152,9 @@ export class RLNInstance {
|
|
192
152
|
idKey: Uint8Array
|
193
153
|
): Promise<RateLimitProof> {
|
194
154
|
if (epoch == undefined) {
|
195
|
-
epoch =
|
155
|
+
epoch = epochIntToBytes(dateToEpoch(new Date()));
|
196
156
|
} else if (epoch instanceof Date) {
|
197
|
-
epoch =
|
157
|
+
epoch = epochIntToBytes(dateToEpoch(epoch));
|
198
158
|
}
|
199
159
|
|
200
160
|
if (epoch.length != 32) throw "invalid epoch";
|
@@ -218,13 +178,16 @@ export class RLNInstance {
|
|
218
178
|
rlnWitness
|
219
179
|
);
|
220
180
|
|
221
|
-
return new
|
181
|
+
return new Proof(proofBytes);
|
222
182
|
}
|
223
183
|
|
224
184
|
verifyProof(proof: RateLimitProof | Uint8Array): boolean {
|
225
|
-
|
226
|
-
|
185
|
+
let pBytes: Uint8Array;
|
186
|
+
if (proof instanceof Uint8Array) {
|
187
|
+
pBytes = proof;
|
188
|
+
} else {
|
189
|
+
pBytes = proofToBytes(proof);
|
227
190
|
}
|
228
|
-
return zerokitRLN.verifyProof(this.zkRLN,
|
191
|
+
return zerokitRLN.verifyProof(this.zkRLN, pBytes);
|
229
192
|
}
|
230
193
|
}
|