2022-09-26 12:08:28 -04:00
|
|
|
import debug from "debug";
|
2022-09-30 14:25:44 +10:00
|
|
|
import { utils } from "js-waku";
|
2022-09-26 12:08:28 -04:00
|
|
|
import {
|
|
|
|
|
Decoder,
|
|
|
|
|
Encoder,
|
|
|
|
|
Message,
|
|
|
|
|
ProtoMessage,
|
2022-09-30 14:25:44 +10:00
|
|
|
RateLimitProof,
|
2022-09-26 12:08:28 -04:00
|
|
|
} from "js-waku/lib/interfaces";
|
2022-09-25 11:40:49 -04:00
|
|
|
|
2022-09-28 14:23:10 +10:00
|
|
|
import { RlnMessage } from "./message.js";
|
2022-09-26 12:08:28 -04:00
|
|
|
import { MembershipKey, RLNInstance } from "./rln.js";
|
|
|
|
|
|
|
|
|
|
const log = debug("waku:message:rln-encoder");
|
2022-09-25 11:40:49 -04:00
|
|
|
|
|
|
|
|
export class RLNEncoder implements Encoder {
|
2022-09-26 12:08:28 -04:00
|
|
|
public contentTopic: string;
|
2022-09-27 13:45:14 +10:00
|
|
|
private readonly idKey: Uint8Array;
|
2022-09-26 12:08:28 -04:00
|
|
|
|
2022-09-25 11:40:49 -04:00
|
|
|
constructor(
|
|
|
|
|
private encoder: Encoder,
|
|
|
|
|
private rlnInstance: RLNInstance,
|
|
|
|
|
private index: number,
|
2022-09-26 12:08:28 -04:00
|
|
|
membershipKey: MembershipKey
|
2022-09-25 11:40:49 -04:00
|
|
|
) {
|
|
|
|
|
if (index < 0) throw "invalid membership index";
|
2022-09-26 12:08:28 -04:00
|
|
|
this.idKey = membershipKey.IDKey;
|
|
|
|
|
this.contentTopic = encoder.contentTopic;
|
2022-09-25 11:40:49 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-30 14:25:44 +10:00
|
|
|
async toWire(message: Partial<Message>): Promise<Uint8Array | undefined> {
|
|
|
|
|
message.rateLimitProof = await this.generateProof(message);
|
|
|
|
|
|
|
|
|
|
return this.encoder.toWire(message);
|
2022-09-25 11:40:49 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-30 14:25:44 +10:00
|
|
|
async toProtoObj(
|
|
|
|
|
message: Partial<Message>
|
|
|
|
|
): Promise<ProtoMessage | undefined> {
|
|
|
|
|
const protoMessage = await this.encoder.toProtoObj(message);
|
2022-09-25 11:40:49 -04:00
|
|
|
if (!protoMessage) return;
|
|
|
|
|
|
2022-09-30 14:25:44 +10:00
|
|
|
protoMessage.rateLimitProof = await this.generateProof(message);
|
|
|
|
|
|
|
|
|
|
return protoMessage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async generateProof(
|
|
|
|
|
message: Partial<Message>
|
|
|
|
|
): Promise<RateLimitProof> {
|
2022-09-27 13:45:14 +10:00
|
|
|
const signal = toRLNSignal(message);
|
2022-09-25 11:40:49 -04:00
|
|
|
|
|
|
|
|
console.time("proof_gen_timer");
|
|
|
|
|
const proof = await this.rlnInstance.generateProof(
|
|
|
|
|
signal,
|
|
|
|
|
this.index,
|
|
|
|
|
message.timestamp,
|
|
|
|
|
this.idKey
|
|
|
|
|
);
|
|
|
|
|
console.timeEnd("proof_gen_timer");
|
2022-09-30 14:25:44 +10:00
|
|
|
return proof;
|
2022-09-25 11:40:49 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-26 12:08:28 -04:00
|
|
|
|
2022-09-28 14:23:10 +10:00
|
|
|
export class RLNDecoder<T extends Message> implements Decoder<RlnMessage<T>> {
|
|
|
|
|
constructor(private rlnInstance: RLNInstance, private decoder: Decoder<T>) {}
|
2022-09-26 12:08:28 -04:00
|
|
|
|
2022-09-28 14:23:10 +10:00
|
|
|
get contentTopic(): string {
|
|
|
|
|
return this.decoder.contentTopic;
|
2022-09-26 12:08:28 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-30 14:25:44 +10:00
|
|
|
fromWireToProtoObj(bytes: Uint8Array): Promise<ProtoMessage | undefined> {
|
|
|
|
|
const protoMessage = this.decoder.fromWireToProtoObj(bytes);
|
2022-09-26 12:08:28 -04:00
|
|
|
log("Message decoded", protoMessage);
|
|
|
|
|
return Promise.resolve(protoMessage);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-30 14:25:44 +10:00
|
|
|
async fromProtoObj(proto: ProtoMessage): Promise<RlnMessage<T> | undefined> {
|
|
|
|
|
const msg: T | undefined = await this.decoder.fromProtoObj(proto);
|
2022-09-28 14:23:10 +10:00
|
|
|
if (!msg) return;
|
|
|
|
|
return new RlnMessage(this.rlnInstance, msg, proto.rateLimitProof);
|
2022-09-26 12:08:28 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-27 13:45:14 +10:00
|
|
|
|
2022-09-30 14:25:44 +10:00
|
|
|
function toRLNSignal(msg: Partial<Message>): Uint8Array {
|
2022-09-27 13:54:44 +10:00
|
|
|
const contentTopicBytes = utils.utf8ToBytes(msg.contentTopic ?? "");
|
2022-09-27 13:45:14 +10:00
|
|
|
return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
|
|
|
|
|
}
|