mirror of
https://github.com/logos-messaging/js-rln.git
synced 2026-01-07 08:03:10 +00:00
Merge pull request #26 from waku-org/proof-attached
This commit is contained in:
commit
378ad04c53
14
package-lock.json
generated
14
package-lock.json
generated
@ -41,7 +41,7 @@
|
||||
"husky": "^7.0.4",
|
||||
"ignore-loader": "^0.1.2",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"js-waku": "^0.29.0-7714812",
|
||||
"js-waku": "^0.29.0-29436ea",
|
||||
"jsdom": "^19.0.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"karma": "^6.3.12",
|
||||
@ -6648,9 +6648,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-waku": {
|
||||
"version": "0.29.0-7714812",
|
||||
"resolved": "https://registry.npmjs.org/js-waku/-/js-waku-0.29.0-7714812.tgz",
|
||||
"integrity": "sha512-pHX7cvrLC8Yw0KxTa8KJlFcE9S5WLkBWqd0pWqBWGCG5mU1Q6LWBZv+rOYuhn9wkCCpjF5jWJvmTohzkGt91XA==",
|
||||
"version": "0.29.0-29436ea",
|
||||
"resolved": "https://registry.npmjs.org/js-waku/-/js-waku-0.29.0-29436ea.tgz",
|
||||
"integrity": "sha512-I2rbC4X0Ho5jnLQp+5V7jqVBk0OY11+mR8zh2HFbPo3m3ifqYaASeMmdE7fFQ/LY0uUFx1qphJq/0X+agD91wA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@chainsafe/libp2p-gossipsub": "^4.1.1",
|
||||
@ -15734,9 +15734,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"js-waku": {
|
||||
"version": "0.29.0-7714812",
|
||||
"resolved": "https://registry.npmjs.org/js-waku/-/js-waku-0.29.0-7714812.tgz",
|
||||
"integrity": "sha512-pHX7cvrLC8Yw0KxTa8KJlFcE9S5WLkBWqd0pWqBWGCG5mU1Q6LWBZv+rOYuhn9wkCCpjF5jWJvmTohzkGt91XA==",
|
||||
"version": "0.29.0-29436ea",
|
||||
"resolved": "https://registry.npmjs.org/js-waku/-/js-waku-0.29.0-29436ea.tgz",
|
||||
"integrity": "sha512-I2rbC4X0Ho5jnLQp+5V7jqVBk0OY11+mR8zh2HFbPo3m3ifqYaASeMmdE7fFQ/LY0uUFx1qphJq/0X+agD91wA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@chainsafe/libp2p-gossipsub": "^4.1.1",
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
"husky": "^7.0.4",
|
||||
"ignore-loader": "^0.1.2",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"js-waku": "^0.29.0-7714812",
|
||||
"js-waku": "^0.29.0-29436ea",
|
||||
"jsdom": "^19.0.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"karma": "^6.3.12",
|
||||
|
||||
@ -1,14 +1,30 @@
|
||||
import { expect } from "chai";
|
||||
import { DecoderV0, EncoderV0 } from "js-waku/lib/waku_message/version_0";
|
||||
import {
|
||||
generatePrivateKey,
|
||||
generateSymmetricKey,
|
||||
getPublicKey,
|
||||
} from "js-waku";
|
||||
import {
|
||||
DecoderV0,
|
||||
EncoderV0,
|
||||
MessageV0,
|
||||
} from "js-waku/lib/waku_message/version_0";
|
||||
import {
|
||||
AsymDecoder,
|
||||
AsymEncoder,
|
||||
SymDecoder,
|
||||
SymEncoder,
|
||||
} from "js-waku/lib/waku_message/version_1";
|
||||
|
||||
import { RLNDecoder, RLNEncoder } from "./codec.js";
|
||||
import { RlnMessage } from "./message.js";
|
||||
|
||||
import * as rln from "./index.js";
|
||||
|
||||
const TestContentTopic = "/test/1/waku-message/utf8";
|
||||
|
||||
describe("js-rln: encoder", () => {
|
||||
it("should attach a proof to a waku message", async function () {
|
||||
describe("RLN codec with version 0", () => {
|
||||
it("toWire", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const index = 0;
|
||||
@ -27,13 +43,57 @@ describe("js-rln: encoder", () => {
|
||||
new DecoderV0(TestContentTopic)
|
||||
);
|
||||
|
||||
const bytes = await rlnEncoder.encode({ payload });
|
||||
const protoResult = await rlnDecoder.decodeProto(bytes!);
|
||||
const bytes = await rlnEncoder.toWire({ payload });
|
||||
|
||||
const msg = (await rlnDecoder.decode(protoResult!))!;
|
||||
expect(bytes).to.not.be.undefined;
|
||||
const protoResult = await rlnDecoder.fromWireToProtoObj(bytes!);
|
||||
|
||||
// Validate proof
|
||||
expect(protoResult).to.not.be.undefined;
|
||||
const msg = (await rlnDecoder.fromProtoObj(protoResult!))!;
|
||||
|
||||
expect(msg.rateLimitProof).to.not.be.undefined;
|
||||
expect(msg.verify()).to.be.true;
|
||||
expect(msg.epoch).to.not.be.undefined;
|
||||
expect(msg.epoch).to.be.gt(0);
|
||||
|
||||
expect(msg.contentTopic).to.eq(TestContentTopic);
|
||||
expect(msg.msg.version).to.eq(0);
|
||||
expect(msg.payload).to.deep.eq(payload);
|
||||
expect(msg.timestamp).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it("toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
new EncoderV0(TestContentTopic),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
new DecoderV0(TestContentTopic)
|
||||
);
|
||||
|
||||
const proto = await rlnEncoder.toProtoObj({ payload });
|
||||
|
||||
expect(proto).to.not.be.undefined;
|
||||
const msg = (await rlnDecoder.fromProtoObj(
|
||||
proto!
|
||||
)) as RlnMessage<MessageV0>;
|
||||
|
||||
expect(msg).to.not.be.undefined;
|
||||
expect(msg.rateLimitProof).to.not.be.undefined;
|
||||
|
||||
expect(msg.verify()).to.be.true;
|
||||
expect(msg.epoch).to.not.be.undefined;
|
||||
expect(msg.epoch).to.be.gt(0);
|
||||
|
||||
expect(msg.contentTopic).to.eq(TestContentTopic);
|
||||
expect(msg.msg.version).to.eq(0);
|
||||
@ -41,3 +101,169 @@ describe("js-rln: encoder", () => {
|
||||
expect(msg.timestamp).to.not.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
describe("RLN codec with version 1", () => {
|
||||
it("Symmetric, toWire", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
new SymEncoder(TestContentTopic, symKey),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
new SymDecoder(TestContentTopic, symKey)
|
||||
);
|
||||
|
||||
const bytes = await rlnEncoder.toWire({ payload });
|
||||
|
||||
expect(bytes).to.not.be.undefined;
|
||||
const protoResult = await rlnDecoder.fromWireToProtoObj(bytes!);
|
||||
|
||||
expect(protoResult).to.not.be.undefined;
|
||||
const msg = (await rlnDecoder.fromProtoObj(protoResult!))!;
|
||||
|
||||
expect(msg.rateLimitProof).to.not.be.undefined;
|
||||
expect(msg.verify()).to.be.true;
|
||||
expect(msg.epoch).to.not.be.undefined;
|
||||
expect(msg.epoch).to.be.gt(0);
|
||||
|
||||
expect(msg.contentTopic).to.eq(TestContentTopic);
|
||||
expect(msg.msg.version).to.eq(1);
|
||||
expect(msg.payload).to.deep.eq(payload);
|
||||
expect(msg.timestamp).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it("Symmetric, toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
new SymEncoder(TestContentTopic, symKey),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
new SymDecoder(TestContentTopic, symKey)
|
||||
);
|
||||
|
||||
const proto = await rlnEncoder.toProtoObj({ payload });
|
||||
|
||||
expect(proto).to.not.be.undefined;
|
||||
const msg = (await rlnDecoder.fromProtoObj(
|
||||
proto!
|
||||
)) as RlnMessage<MessageV0>;
|
||||
|
||||
expect(msg).to.not.be.undefined;
|
||||
expect(msg.rateLimitProof).to.not.be.undefined;
|
||||
|
||||
expect(msg.verify()).to.be.true;
|
||||
expect(msg.epoch).to.not.be.undefined;
|
||||
expect(msg.epoch).to.be.gt(0);
|
||||
|
||||
expect(msg.contentTopic).to.eq(TestContentTopic);
|
||||
expect(msg.msg.version).to.eq(1);
|
||||
expect(msg.payload).to.deep.eq(payload);
|
||||
expect(msg.timestamp).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it("Asymmetric, toWire", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
new AsymEncoder(TestContentTopic, publicKey),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
new AsymDecoder(TestContentTopic, privateKey)
|
||||
);
|
||||
|
||||
const bytes = await rlnEncoder.toWire({ payload });
|
||||
|
||||
expect(bytes).to.not.be.undefined;
|
||||
const protoResult = await rlnDecoder.fromWireToProtoObj(bytes!);
|
||||
|
||||
expect(protoResult).to.not.be.undefined;
|
||||
const msg = (await rlnDecoder.fromProtoObj(protoResult!))!;
|
||||
|
||||
expect(msg.rateLimitProof).to.not.be.undefined;
|
||||
expect(msg.verify()).to.be.true;
|
||||
expect(msg.epoch).to.not.be.undefined;
|
||||
expect(msg.epoch).to.be.gt(0);
|
||||
|
||||
expect(msg.contentTopic).to.eq(TestContentTopic);
|
||||
expect(msg.msg.version).to.eq(1);
|
||||
expect(msg.payload).to.deep.eq(payload);
|
||||
expect(msg.timestamp).to.not.be.undefined;
|
||||
});
|
||||
|
||||
it("Asymmetric, toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
new AsymEncoder(TestContentTopic, publicKey),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
new AsymDecoder(TestContentTopic, privateKey)
|
||||
);
|
||||
|
||||
const proto = await rlnEncoder.toProtoObj({ payload });
|
||||
|
||||
expect(proto).to.not.be.undefined;
|
||||
const msg = (await rlnDecoder.fromProtoObj(
|
||||
proto!
|
||||
)) as RlnMessage<MessageV0>;
|
||||
|
||||
expect(msg).to.not.be.undefined;
|
||||
expect(msg.rateLimitProof).to.not.be.undefined;
|
||||
|
||||
expect(msg.verify()).to.be.true;
|
||||
expect(msg.epoch).to.not.be.undefined;
|
||||
expect(msg.epoch).to.be.gt(0);
|
||||
|
||||
expect(msg.contentTopic).to.eq(TestContentTopic);
|
||||
expect(msg.msg.version).to.eq(1);
|
||||
expect(msg.payload).to.deep.eq(payload);
|
||||
expect(msg.timestamp).to.not.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
40
src/codec.ts
40
src/codec.ts
@ -1,10 +1,11 @@
|
||||
import debug from "debug";
|
||||
import { proto_message, utils } from "js-waku";
|
||||
import { utils } from "js-waku";
|
||||
import {
|
||||
Decoder,
|
||||
Encoder,
|
||||
Message,
|
||||
ProtoMessage,
|
||||
RateLimitProof,
|
||||
} from "js-waku/lib/interfaces";
|
||||
|
||||
import { RlnMessage } from "./message.js";
|
||||
@ -27,16 +28,26 @@ export class RLNEncoder implements Encoder {
|
||||
this.contentTopic = encoder.contentTopic;
|
||||
}
|
||||
|
||||
async encode(message: Message): Promise<Uint8Array | undefined> {
|
||||
const protoMessage = await this.encodeProto(message);
|
||||
if (!protoMessage) return;
|
||||
return proto_message.WakuMessage.encode(protoMessage);
|
||||
async toWire(message: Partial<Message>): Promise<Uint8Array | undefined> {
|
||||
message.rateLimitProof = await this.generateProof(message);
|
||||
|
||||
return this.encoder.toWire(message);
|
||||
}
|
||||
|
||||
async encodeProto(message: Message): Promise<ProtoMessage | undefined> {
|
||||
const protoMessage = await this.encoder.encodeProto(message);
|
||||
async toProtoObj(
|
||||
message: Partial<Message>
|
||||
): Promise<ProtoMessage | undefined> {
|
||||
const protoMessage = await this.encoder.toProtoObj(message);
|
||||
if (!protoMessage) return;
|
||||
|
||||
protoMessage.rateLimitProof = await this.generateProof(message);
|
||||
|
||||
return protoMessage;
|
||||
}
|
||||
|
||||
private async generateProof(
|
||||
message: Partial<Message>
|
||||
): Promise<RateLimitProof> {
|
||||
const signal = toRLNSignal(message);
|
||||
|
||||
console.time("proof_gen_timer");
|
||||
@ -47,10 +58,7 @@ export class RLNEncoder implements Encoder {
|
||||
this.idKey
|
||||
);
|
||||
console.timeEnd("proof_gen_timer");
|
||||
|
||||
protoMessage.rateLimitProof = proof;
|
||||
|
||||
return protoMessage;
|
||||
return proof;
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,20 +69,20 @@ export class RLNDecoder<T extends Message> implements Decoder<RlnMessage<T>> {
|
||||
return this.decoder.contentTopic;
|
||||
}
|
||||
|
||||
decodeProto(bytes: Uint8Array): Promise<ProtoMessage | undefined> {
|
||||
const protoMessage = proto_message.WakuMessage.decode(bytes);
|
||||
fromWireToProtoObj(bytes: Uint8Array): Promise<ProtoMessage | undefined> {
|
||||
const protoMessage = this.decoder.fromWireToProtoObj(bytes);
|
||||
log("Message decoded", protoMessage);
|
||||
return Promise.resolve(protoMessage);
|
||||
}
|
||||
|
||||
async decode(proto: ProtoMessage): Promise<RlnMessage<T> | undefined> {
|
||||
const msg: T | undefined = await this.decoder.decode(proto);
|
||||
async fromProtoObj(proto: ProtoMessage): Promise<RlnMessage<T> | undefined> {
|
||||
const msg: T | undefined = await this.decoder.fromProtoObj(proto);
|
||||
if (!msg) return;
|
||||
return new RlnMessage(this.rlnInstance, msg, proto.rateLimitProof);
|
||||
}
|
||||
}
|
||||
|
||||
function toRLNSignal(msg: Message): Uint8Array {
|
||||
function toRLNSignal(msg: Partial<Message>): Uint8Array {
|
||||
const contentTopicBytes = utils.utf8ToBytes(msg.contentTopic ?? "");
|
||||
return new Uint8Array([...(msg.payload ?? []), ...contentTopicBytes]);
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export class RlnMessage<T extends Message> implements Message {
|
||||
constructor(
|
||||
public rlnInstance: RLNInstance,
|
||||
public msg: T,
|
||||
public rateLimitProof?: RateLimitProof
|
||||
public rateLimitProof: RateLimitProof | undefined
|
||||
) {}
|
||||
|
||||
public verify(): boolean | undefined {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user