mirror of
https://github.com/logos-messaging/js-rln.git
synced 2026-01-12 10:33:10 +00:00
feat: use identity credentials, and expose hash, bulk insert and delete members functions
Also update the resources and karma.conf because proof generation is taking longer than usual
This commit is contained in:
parent
7e0966aef7
commit
f20bdbb9a9
10
README.md
10
README.md
@ -70,10 +70,10 @@ import * as rln from "@waku/rln";
|
||||
const rlnInstance = await rln.create();
|
||||
```
|
||||
|
||||
### Generating RLN Membership Keypair
|
||||
#### Generating RLN membership credentials
|
||||
|
||||
```js
|
||||
let memKeys = rlnInstance.generateMembershipKey();
|
||||
let credentials = rlnInstance.generateIdentityCredentials();
|
||||
```
|
||||
|
||||
### Generating RLN Membership Keypair Using a Seed
|
||||
@ -81,13 +81,13 @@ let memKeys = rlnInstance.generateMembershipKey();
|
||||
This can be used to generate credentials from a signature hash (e.g. signed by an Ethereum account).
|
||||
|
||||
```js
|
||||
let memKeys = rlnInstance.generateSeededMembershipKey(seed);
|
||||
let credentials = rlnInstance.generateSeededIdentityCredentials(seed);
|
||||
```
|
||||
|
||||
### Adding Membership Keys Into Merkle Tree
|
||||
|
||||
```js
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credentials.IDCommitment);
|
||||
```
|
||||
|
||||
### Generating a Proof
|
||||
@ -106,7 +106,7 @@ const proof = await rlnInstance.generateProof(
|
||||
uint8Msg,
|
||||
index,
|
||||
epoch,
|
||||
memKeys.IDKey
|
||||
credentials.IDSecretHash
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as rln from "@waku/rln";
|
||||
|
||||
rln.create().then(async rlnInstance => {
|
||||
let memKeys = rlnInstance.generateMembershipKey();
|
||||
let credentials = rlnInstance.generateIdentityCredentials();
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
const index = 5
|
||||
@ -10,11 +10,11 @@ rln.create().then(async rlnInstance => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (i == index) {
|
||||
// insert the current peer's pk
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credentials.IDCommitment);
|
||||
} else {
|
||||
// create a new key pair
|
||||
let memKeys = rlnInstance.generateMembershipKey(); // TODO: handle error
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
let credentials = rlnInstance.generateIdentityCredentials(); // TODO: handle error
|
||||
rlnInstance.insertMember(credentials.IDCommitment);
|
||||
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@ rln.create().then(async rlnInstance => {
|
||||
|
||||
console.log("Generating proof...");
|
||||
console.time("proof_gen_timer");
|
||||
let proof = await rlnInstance.generateRLNProof(uint8Msg, index, epoch, memKeys.IDKey)
|
||||
let proof = await rlnInstance.generateRLNProof(uint8Msg, index, epoch, credentials.IDSecretHash)
|
||||
console.timeEnd("proof_gen_timer");
|
||||
console.log("Proof", proof)
|
||||
|
||||
|
||||
@ -30,10 +30,11 @@ module.exports = function (config) {
|
||||
envPreprocessor: ["CI"],
|
||||
reporters: ["progress"],
|
||||
browsers: ["ChromeHeadless"],
|
||||
pingTimeout: 60000,
|
||||
singleRun: true,
|
||||
client: {
|
||||
mocha: {
|
||||
timeout: 6000, // Default is 2s
|
||||
timeout: 60000, // Default is 2s
|
||||
},
|
||||
},
|
||||
webpack: {
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@waku/rln",
|
||||
"version": "0.0.14",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@waku/rln",
|
||||
"version": "0.0.14",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"dependencies": {
|
||||
"@waku/utils": "^0.0.4",
|
||||
"@waku/zerokit-rln-wasm": "^0.0.5",
|
||||
"@waku/zerokit-rln-wasm": "^0.0.10",
|
||||
"ethers": "^5.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -2942,9 +2942,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@waku/zerokit-rln-wasm": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.5.tgz",
|
||||
"integrity": "sha512-uZHZRk06WrnqJJOVwIIKtsjWf2d6g2JpK8FtC0lHg4JJkOxhJy0pgEIuBCPw8Je4MpF9FCtIO/ww7xicdlC2GA=="
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.10.tgz",
|
||||
"integrity": "sha512-qegIK1P54mxEp59uTa8C0/zidUffLc2Iee61yiKRIuGJDui2mQ+0V+KzPSPImKpIoqfVLT192EqgZkqPmj8VEw=="
|
||||
},
|
||||
"node_modules/@web/rollup-plugin-import-meta-assets": {
|
||||
"version": "1.0.7",
|
||||
@ -13629,9 +13629,9 @@
|
||||
}
|
||||
},
|
||||
"@waku/zerokit-rln-wasm": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.5.tgz",
|
||||
"integrity": "sha512-uZHZRk06WrnqJJOVwIIKtsjWf2d6g2JpK8FtC0lHg4JJkOxhJy0pgEIuBCPw8Je4MpF9FCtIO/ww7xicdlC2GA=="
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.10.tgz",
|
||||
"integrity": "sha512-qegIK1P54mxEp59uTa8C0/zidUffLc2Iee61yiKRIuGJDui2mQ+0V+KzPSPImKpIoqfVLT192EqgZkqPmj8VEw=="
|
||||
},
|
||||
"@web/rollup-plugin-import-meta-assets": {
|
||||
"version": "1.0.7",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@waku/rln",
|
||||
"version": "0.0.14",
|
||||
"version": "0.1.0",
|
||||
"description": "Rate Limit Nullifier for js-waku",
|
||||
"types": "./dist/index.d.ts",
|
||||
"module": "./dist/index.js",
|
||||
@ -130,7 +130,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@waku/utils": "^0.0.4",
|
||||
"@waku/zerokit-rln-wasm": "^0.0.5",
|
||||
"@waku/zerokit-rln-wasm": "^0.0.10",
|
||||
"ethers": "^5.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,17 +35,17 @@ const EMPTY_PUBSUB_TOPIC = "";
|
||||
describe("RLN codec with version 0", () => {
|
||||
it("toWire", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const rlnEncoder = createRLNEncoder({
|
||||
encoder: createEncoder({ contentTopic: TestContentTopic }),
|
||||
rlnInstance,
|
||||
index,
|
||||
membershipKey: memKeys,
|
||||
credential,
|
||||
});
|
||||
const rlnDecoder = createRLNDecoder({
|
||||
rlnInstance,
|
||||
@ -76,17 +76,17 @@ describe("RLN codec with version 0", () => {
|
||||
|
||||
it("toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
createEncoder({ contentTopic: TestContentTopic }),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
credential
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
@ -119,11 +119,11 @@ describe("RLN codec with version 0", () => {
|
||||
describe("RLN codec with version 1", () => {
|
||||
it("Symmetric, toWire", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
@ -134,7 +134,7 @@ describe("RLN codec with version 1", () => {
|
||||
}),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
credential
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
@ -166,11 +166,11 @@ describe("RLN codec with version 1", () => {
|
||||
|
||||
it("Symmetric, toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
@ -181,7 +181,7 @@ describe("RLN codec with version 1", () => {
|
||||
}),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
credential
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
@ -212,11 +212,11 @@ describe("RLN codec with version 1", () => {
|
||||
|
||||
it("Asymmetric, toWire", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
@ -228,7 +228,7 @@ describe("RLN codec with version 1", () => {
|
||||
}),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
credential
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
@ -260,11 +260,11 @@ describe("RLN codec with version 1", () => {
|
||||
|
||||
it("Asymmetric, toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
@ -276,7 +276,7 @@ describe("RLN codec with version 1", () => {
|
||||
}),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
credential
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
@ -309,17 +309,17 @@ describe("RLN codec with version 1", () => {
|
||||
describe("RLN Codec - epoch", () => {
|
||||
it("toProtoObj", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
const index = 0;
|
||||
const payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
|
||||
const rlnEncoder = new RLNEncoder(
|
||||
createEncoder({ contentTopic: TestContentTopic }),
|
||||
rlnInstance,
|
||||
index,
|
||||
memKeys
|
||||
credential
|
||||
);
|
||||
const rlnDecoder = new RLNDecoder(
|
||||
rlnInstance,
|
||||
|
||||
14
src/codec.ts
14
src/codec.ts
@ -9,21 +9,21 @@ import type {
|
||||
import debug from "debug";
|
||||
|
||||
import { RlnMessage, toRLNSignal } from "./message.js";
|
||||
import { MembershipKey, RLNInstance } from "./rln.js";
|
||||
import { IdentityCredential, RLNInstance } from "./rln.js";
|
||||
|
||||
const log = debug("waku:rln:encoder");
|
||||
|
||||
export class RLNEncoder implements IEncoder {
|
||||
private readonly idKey: Uint8Array;
|
||||
private readonly idSecretHash: Uint8Array;
|
||||
|
||||
constructor(
|
||||
private encoder: IEncoder,
|
||||
private rlnInstance: RLNInstance,
|
||||
private index: number,
|
||||
membershipKey: MembershipKey
|
||||
identityCredential: IdentityCredential
|
||||
) {
|
||||
if (index < 0) throw "invalid membership index";
|
||||
this.idKey = membershipKey.IDKey;
|
||||
this.idSecretHash = identityCredential.IDSecretHash;
|
||||
}
|
||||
|
||||
async toWire(message: IMessage): Promise<Uint8Array | undefined> {
|
||||
@ -50,7 +50,7 @@ export class RLNEncoder implements IEncoder {
|
||||
signal,
|
||||
this.index,
|
||||
message.timestamp,
|
||||
this.idKey
|
||||
this.idSecretHash
|
||||
);
|
||||
console.timeEnd("proof_gen_timer");
|
||||
return proof;
|
||||
@ -69,7 +69,7 @@ type RLNEncoderOptions = {
|
||||
encoder: IEncoder;
|
||||
rlnInstance: RLNInstance;
|
||||
index: number;
|
||||
membershipKey: MembershipKey;
|
||||
credential: IdentityCredential;
|
||||
};
|
||||
|
||||
export const createRLNEncoder = (options: RLNEncoderOptions): RLNEncoder => {
|
||||
@ -77,7 +77,7 @@ export const createRLNEncoder = (options: RLNEncoderOptions): RLNEncoder => {
|
||||
options.encoder,
|
||||
options.rlnInstance,
|
||||
options.index,
|
||||
options.membershipKey
|
||||
options.credential
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ describe("js-rln", () => {
|
||||
it("should verify a proof", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
|
||||
const memKeys = rlnInstance.generateMembershipKey();
|
||||
const credential = rlnInstance.generateIdentityCredentials();
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
const index = 5;
|
||||
@ -15,11 +15,11 @@ describe("js-rln", () => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (i == index) {
|
||||
// insert the current peer's pk
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
} else {
|
||||
// create a new key pair
|
||||
rlnInstance.insertMember(
|
||||
rlnInstance.generateMembershipKey().IDCommitment
|
||||
rlnInstance.generateIdentityCredentials().IDCommitment
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@ describe("js-rln", () => {
|
||||
uint8Msg,
|
||||
index,
|
||||
epoch,
|
||||
memKeys.IDKey
|
||||
credential.IDSecretHash
|
||||
);
|
||||
|
||||
try {
|
||||
@ -61,7 +61,7 @@ describe("js-rln", () => {
|
||||
it("should verify a proof with a seeded membership key generation", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const seed = "This is a test seed";
|
||||
const memKeys = rlnInstance.generateSeededMembershipKey(seed);
|
||||
const credential = rlnInstance.generateSeededIdentityCredential(seed);
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
const index = 5;
|
||||
@ -70,11 +70,11 @@ describe("js-rln", () => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (i == index) {
|
||||
// insert the current peer's pk
|
||||
rlnInstance.insertMember(memKeys.IDCommitment);
|
||||
rlnInstance.insertMember(credential.IDCommitment);
|
||||
} else {
|
||||
// create a new key pair
|
||||
rlnInstance.insertMember(
|
||||
rlnInstance.generateMembershipKey().IDCommitment
|
||||
rlnInstance.generateIdentityCredentials().IDCommitment
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -92,7 +92,7 @@ describe("js-rln", () => {
|
||||
uint8Msg,
|
||||
index,
|
||||
epoch,
|
||||
memKeys.IDKey
|
||||
credential.IDSecretHash
|
||||
);
|
||||
|
||||
try {
|
||||
@ -116,14 +116,20 @@ describe("js-rln", () => {
|
||||
it("should generate the same membership key if the same seed is provided", async function () {
|
||||
const rlnInstance = await rln.create();
|
||||
const seed = "This is a test seed";
|
||||
const memKeys1 = rlnInstance.generateSeededMembershipKey(seed);
|
||||
const memKeys2 = rlnInstance.generateSeededMembershipKey(seed);
|
||||
const memKeys1 = rlnInstance.generateSeededIdentityCredential(seed);
|
||||
const memKeys2 = rlnInstance.generateSeededIdentityCredential(seed);
|
||||
|
||||
memKeys1.IDCommitment.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDCommitment[index]);
|
||||
});
|
||||
memKeys1.IDKey.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDKey[index]);
|
||||
memKeys1.IDNullifier.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDNullifier[index]);
|
||||
});
|
||||
memKeys1.IDSecretHash.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDSecretHash[index]);
|
||||
});
|
||||
memKeys1.IDTrapdoor.forEach((element, index) => {
|
||||
expect(element).to.equal(memKeys2.IDTrapdoor[index]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
11
src/index.ts
11
src/index.ts
@ -1,7 +1,11 @@
|
||||
import { RLNDecoder, RLNEncoder } from "./codec.js";
|
||||
import { GOERLI_CONTRACT, RLN_ABI } from "./constants.js";
|
||||
import { Proof, RLNInstance } from "./rln.js";
|
||||
import { MembershipKey } from "./rln.js";
|
||||
import {
|
||||
IdentityCredential,
|
||||
Proof,
|
||||
ProofMetadata,
|
||||
RLNInstance,
|
||||
} from "./rln.js";
|
||||
import { RLNContract } from "./rln_contract.js";
|
||||
|
||||
// reexport the create function, dynamically imported from rln.ts
|
||||
@ -15,8 +19,9 @@ export async function create(): Promise<RLNInstance> {
|
||||
|
||||
export {
|
||||
RLNInstance,
|
||||
MembershipKey,
|
||||
IdentityCredential,
|
||||
Proof,
|
||||
ProofMetadata,
|
||||
RLNEncoder,
|
||||
RLNDecoder,
|
||||
RLNContract,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1,120 +1,112 @@
|
||||
const verificationKey = {
|
||||
"protocol": "groth16",
|
||||
"curve": "bn128",
|
||||
"nPublic": 6,
|
||||
"vk_alpha_1": [
|
||||
"1805378556360488226980822394597799963030511477964155500103132920745199284516",
|
||||
"11990395240534218699464972016456017378439762088320057798320175886595281336136",
|
||||
"1"
|
||||
protocol: "groth16",
|
||||
curve: "bn128",
|
||||
nPublic: 6,
|
||||
vk_alpha_1: [
|
||||
"20124996762962216725442980738609010303800849578410091356605067053491763969391",
|
||||
"9118593021526896828671519912099489027245924097793322973632351264852174143923",
|
||||
"1",
|
||||
],
|
||||
"vk_beta_2": [
|
||||
vk_beta_2: [
|
||||
[
|
||||
"11031529986141021025408838211017932346992429731488270384177563837022796743627",
|
||||
"16042159910707312759082561183373181639420894978640710177581040523252926273854"
|
||||
"4693952934005375501364248788849686435240706020501681709396105298107971354382",
|
||||
"14346958885444710485362620645446987998958218205939139994511461437152241966681",
|
||||
],
|
||||
[
|
||||
"20112698439519222240302944148895052359035104222313380895334495118294612255131",
|
||||
"19441583024670359810872018179190533814486480928824742448673677460151702019379"
|
||||
"16851772916911573982706166384196538392731905827088356034885868448550849804972",
|
||||
"823612331030938060799959717749043047845343400798220427319188951998582076532",
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
["1", "0"],
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
vk_gamma_2: [
|
||||
[
|
||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634",
|
||||
],
|
||||
[
|
||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531",
|
||||
],
|
||||
["1", "0"],
|
||||
],
|
||||
vk_delta_2: [
|
||||
[
|
||||
"8353516066399360694538747105302262515182301251524941126222712285088022964076",
|
||||
"9329524012539638256356482961742014315122377605267454801030953882967973561832",
|
||||
],
|
||||
[
|
||||
"16805391589556134376869247619848130874761233086443465978238468412168162326401",
|
||||
"10111259694977636294287802909665108497237922060047080343914303287629927847739",
|
||||
],
|
||||
["1", "0"],
|
||||
],
|
||||
vk_alphabeta_12: [
|
||||
[
|
||||
[
|
||||
"12608968655665301215455851857466367636344427685631271961542642719683786103711",
|
||||
"9849575605876329747382930567422916152871921500826003490242628251047652318086",
|
||||
],
|
||||
[
|
||||
"6322029441245076030714726551623552073612922718416871603535535085523083939021",
|
||||
"8700115492541474338049149013125102281865518624059015445617546140629435818912",
|
||||
],
|
||||
[
|
||||
"10674973475340072635573101639867487770811074181475255667220644196793546640210",
|
||||
"2926286967251299230490668407790788696102889214647256022788211245826267484824",
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
"9660441540778523475944706619139394922744328902833875392144658911530830074820",
|
||||
"19548113127774514328631808547691096362144426239827206966690021428110281506546",
|
||||
],
|
||||
[
|
||||
"1870837942477655969123169532603615788122896469891695773961478956740992497097",
|
||||
"12536105729661705698805725105036536744930776470051238187456307227425796690780",
|
||||
],
|
||||
[
|
||||
"21811903352654147452884857281720047789720483752548991551595462057142824037334",
|
||||
"19021616763967199151052893283384285352200445499680068407023236283004353578353",
|
||||
],
|
||||
],
|
||||
],
|
||||
IC: [
|
||||
[
|
||||
"11992897507809711711025355300535923222599547639134311050809253678876341466909",
|
||||
"17181525095924075896332561978747020491074338784673526378866503154966799128110",
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
"1948496782571164085469528023647105317580208688174386157591917599801657832035",
|
||||
"20445814069256658101339037520922621162739470138213615104905368409238414511981"
|
||||
],
|
||||
[
|
||||
"10024680869920840984813249386422727863826862577760330492647062850849851925340",
|
||||
"10512156247842686783409460795717734694774542185222602679117887145206209285142"
|
||||
],
|
||||
[
|
||||
"17018665030246167677911144513385572506766200776123272044534328594850561667818",
|
||||
"18601114175490465275436712413925513066546725461375425769709566180981674884464",
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"18799470100699658367834559797874857804183288553462108031963980039244731716542",
|
||||
"13064227487174191981628537974951887429496059857753101852163607049188825592007",
|
||||
"1",
|
||||
],
|
||||
[
|
||||
"17432501889058124609368103715904104425610382063762621017593209214189134571156",
|
||||
"13406815149699834788256141097399354592751313348962590382887503595131085938635",
|
||||
"1",
|
||||
],
|
||||
[
|
||||
"10320964835612716439094703312987075811498239445882526576970512041988148264481",
|
||||
"9024164961646353611176283204118089412001502110138072989569118393359029324867",
|
||||
"1",
|
||||
],
|
||||
[
|
||||
"718355081067365548229685160476620267257521491773976402837645005858953849298",
|
||||
"14635482993933988261008156660773180150752190597753512086153001683711587601974",
|
||||
"1",
|
||||
],
|
||||
[
|
||||
"11777720285956632126519898515392071627539405001940313098390150593689568177535",
|
||||
"8483603647274280691250972408211651407952870456587066148445913156086740744515",
|
||||
"1",
|
||||
],
|
||||
],
|
||||
"vk_alphabeta_12": [
|
||||
[
|
||||
[
|
||||
"5151991366823434428398919091000210787450832786814248297320989361921939794156",
|
||||
"15735191313289001022885148627913534790382722933676436876510746491415970766821"
|
||||
],
|
||||
[
|
||||
"3387907257437913904447588318761906430938415556102110876587455322225272831272",
|
||||
"1998779853452712881084781956683721603875246565720647583735935725110674288056"
|
||||
],
|
||||
[
|
||||
"14280074182991498185075387990446437410077692353432005297922275464876153151820",
|
||||
"17092408446352310039633488224969232803092763095456307462247653153107223117633"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"4359046709531668109201634396816565829237358165496082832279660960675584351266",
|
||||
"4511888308846208349307186938266411423935335853916317436093178288331845821336"
|
||||
],
|
||||
[
|
||||
"11429499807090785857812316277335883295048773373068683863667725283965356423273",
|
||||
"16232274853200678548795010078253506586114563833318973594428907292096178657392"
|
||||
],
|
||||
[
|
||||
"18068999605870933925311275504102553573815570223888590384919752303726860800970",
|
||||
"17309569111965782732372130116757295842160193489132771344011460471298173784984"
|
||||
]
|
||||
]
|
||||
],
|
||||
"IC": [
|
||||
[
|
||||
"18693301901828818437917730940595978397160482710354161265484535387752523310572",
|
||||
"17985273354976640088538673802000794244421192643855111089693820179790551470769",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21164641723988537620541455173278629777250883365474191521194244273980931825942",
|
||||
"998385854410718613441067082771678946155853656328717326195057262123686425518",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21666968581672145768705229094968410656430989593283335488162701230986314747515",
|
||||
"17996457608540683483506630273632100555125353447506062045735279661096094677264",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20137761979695192602424300886442379728165712610493092740175904438282083668117",
|
||||
"19184814924890679891263780109959113289320127263583260218200636509492157834679",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10943171273393803842589314082509655332154393332394322726077270895078286354146",
|
||||
"10872472035685319847811233167729172672344935625121511932198535224727331126439",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13049169779481227658517545034348883391527506091990880778783387628208561946597",
|
||||
"10083689369261379027228809473568899816311684698866922944902456565434209079955",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19633516378466409167014413361365552102431118630694133723053441455184566611083",
|
||||
"8059525100726933978719058611146131904598011633549012007359165766216730722269",
|
||||
"1"
|
||||
]
|
||||
]
|
||||
}
|
||||
export default verificationKey
|
||||
};
|
||||
|
||||
export default verificationKey;
|
||||
|
||||
103
src/rln.ts
103
src/rln.ts
@ -66,18 +66,29 @@ export async function create(): Promise<RLNInstance> {
|
||||
return new RLNInstance(zkRLN, witnessCalculator);
|
||||
}
|
||||
|
||||
export class MembershipKey {
|
||||
export class IdentityCredential {
|
||||
constructor(
|
||||
public readonly IDKey: Uint8Array,
|
||||
public readonly IDTrapdoor: Uint8Array,
|
||||
public readonly IDNullifier: Uint8Array,
|
||||
public readonly IDSecretHash: Uint8Array,
|
||||
public readonly IDCommitment: Uint8Array,
|
||||
public readonly IDCommitmentBigInt: bigint
|
||||
) {}
|
||||
|
||||
static fromBytes(memKeys: Uint8Array): MembershipKey {
|
||||
const idKey = memKeys.subarray(0, 32);
|
||||
const idCommitment = memKeys.subarray(32);
|
||||
static fromBytes(memKeys: Uint8Array): IdentityCredential {
|
||||
const idTrapdoor = memKeys.subarray(0, 32);
|
||||
const idNullifier = memKeys.subarray(32, 64);
|
||||
const idSecretHash = memKeys.subarray(64, 96);
|
||||
const idCommitment = memKeys.subarray(96);
|
||||
const idCommitmentBigInt = buildBigIntFromUint8Array(idCommitment);
|
||||
return new MembershipKey(idKey, idCommitment, idCommitmentBigInt);
|
||||
|
||||
return new IdentityCredential(
|
||||
idTrapdoor,
|
||||
idNullifier,
|
||||
idSecretHash,
|
||||
idCommitment,
|
||||
idCommitmentBigInt
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,6 +100,14 @@ const shareYOffset = shareXOffset + 32;
|
||||
const nullifierOffset = shareYOffset + 32;
|
||||
const rlnIdentifierOffset = nullifierOffset + 32;
|
||||
|
||||
export class ProofMetadata {
|
||||
constructor(
|
||||
public readonly nullifier: Uint8Array,
|
||||
public readonly shareX: Uint8Array,
|
||||
public readonly shareY: Uint8Array,
|
||||
public readonly externalNullifier: Uint8Array
|
||||
) {}
|
||||
}
|
||||
export class Proof implements IRateLimitProof {
|
||||
readonly proof: Uint8Array;
|
||||
readonly merkleRoot: Uint8Array;
|
||||
@ -112,6 +131,16 @@ export class Proof implements IRateLimitProof {
|
||||
rlnIdentifierOffset
|
||||
);
|
||||
}
|
||||
|
||||
extractMetadata(): ProofMetadata {
|
||||
const externalNullifier = poseidonHash(this.epoch, this.rlnIdentifier);
|
||||
return new ProofMetadata(
|
||||
this.nullifier,
|
||||
this.shareX,
|
||||
this.shareY,
|
||||
externalNullifier
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function proofToBytes(p: IRateLimitProof): Uint8Array {
|
||||
@ -126,30 +155,60 @@ export function proofToBytes(p: IRateLimitProof): Uint8Array {
|
||||
);
|
||||
}
|
||||
|
||||
export function poseidonHash(...input: Array<Uint8Array>): Uint8Array {
|
||||
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
|
||||
const lenPrefixedData = concatenate(inputLen, ...input);
|
||||
return zerokitRLN.poseidonHash(lenPrefixedData);
|
||||
}
|
||||
|
||||
export function sha256(input: Uint8Array): Uint8Array {
|
||||
const inputLen = writeUIntLE(new Uint8Array(8), input.length, 0, 8);
|
||||
const lenPrefixedData = concatenate(inputLen, input);
|
||||
return zerokitRLN.hash(lenPrefixedData);
|
||||
}
|
||||
|
||||
export class RLNInstance {
|
||||
constructor(
|
||||
private zkRLN: number,
|
||||
private witnessCalculator: WitnessCalculator
|
||||
) {}
|
||||
|
||||
generateMembershipKey(): MembershipKey {
|
||||
const memKeys = zerokitRLN.generateMembershipKey(this.zkRLN);
|
||||
return MembershipKey.fromBytes(memKeys);
|
||||
generateIdentityCredentials(): IdentityCredential {
|
||||
const memKeys = zerokitRLN.generateExtendedMembershipKey(this.zkRLN); // TODO: rename this function in zerokit rln-wasm
|
||||
return IdentityCredential.fromBytes(memKeys);
|
||||
}
|
||||
|
||||
generateSeededMembershipKey(seed: string): MembershipKey {
|
||||
generateSeededIdentityCredential(seed: string): IdentityCredential {
|
||||
const seedBytes = stringEncoder.encode(seed);
|
||||
const memKeys = zerokitRLN.generateSeededMembershipKey(
|
||||
// TODO: rename this function in zerokit rln-wasm
|
||||
const memKeys = zerokitRLN.generateSeededExtendedMembershipKey(
|
||||
this.zkRLN,
|
||||
seedBytes
|
||||
);
|
||||
return MembershipKey.fromBytes(memKeys);
|
||||
return IdentityCredential.fromBytes(memKeys);
|
||||
}
|
||||
|
||||
insertMember(idCommitment: Uint8Array): void {
|
||||
zerokitRLN.insertMember(this.zkRLN, idCommitment);
|
||||
}
|
||||
|
||||
insertMembers(index: number, ...idCommitments: Array<Uint8Array>): void {
|
||||
// serializes a seq of IDCommitments to a byte seq
|
||||
// the order of serialization is |id_commitment_len<8>|id_commitment<var>|
|
||||
const idCommitmentLen = writeUIntLE(
|
||||
new Uint8Array(8),
|
||||
idCommitments.length,
|
||||
0,
|
||||
8
|
||||
);
|
||||
const idCommitmentBytes = concatenate(idCommitmentLen, ...idCommitments);
|
||||
zerokitRLN.setLeavesFrom(this.zkRLN, index, idCommitmentBytes);
|
||||
}
|
||||
|
||||
deleteMember(index: number): void {
|
||||
zerokitRLN.deleteLeaf(this.zkRLN, index);
|
||||
}
|
||||
|
||||
getMerkleRoot(): Uint8Array {
|
||||
return zerokitRLN.getRoot(this.zkRLN);
|
||||
}
|
||||
@ -174,7 +233,7 @@ export class RLNInstance {
|
||||
msg: Uint8Array,
|
||||
index: number,
|
||||
epoch: Uint8Array | Date | undefined,
|
||||
idKey: Uint8Array
|
||||
idSecretHash: Uint8Array
|
||||
): Promise<IRateLimitProof> {
|
||||
if (epoch == undefined) {
|
||||
epoch = epochIntToBytes(dateToEpoch(new Date()));
|
||||
@ -183,10 +242,15 @@ export class RLNInstance {
|
||||
}
|
||||
|
||||
if (epoch.length != 32) throw "invalid epoch";
|
||||
if (idKey.length != 32) throw "invalid id key";
|
||||
if (idSecretHash.length != 32) throw "invalid id secret hash";
|
||||
if (index < 0) throw "index must be >= 0";
|
||||
|
||||
const serialized_msg = this.serializeMessage(msg, index, epoch, idKey);
|
||||
const serialized_msg = this.serializeMessage(
|
||||
msg,
|
||||
index,
|
||||
epoch,
|
||||
idSecretHash
|
||||
);
|
||||
const rlnWitness = zerokitRLN.getSerializedRLNWitness(
|
||||
this.zkRLN,
|
||||
serialized_msg
|
||||
@ -228,7 +292,8 @@ export class RLNInstance {
|
||||
|
||||
verifyWithRoots(
|
||||
proof: IRateLimitProof | Uint8Array,
|
||||
msg: Uint8Array
|
||||
msg: Uint8Array,
|
||||
...roots: Array<Uint8Array>
|
||||
): boolean {
|
||||
let pBytes: Uint8Array;
|
||||
if (proof instanceof Uint8Array) {
|
||||
@ -236,17 +301,15 @@ export class RLNInstance {
|
||||
} else {
|
||||
pBytes = proofToBytes(proof);
|
||||
}
|
||||
|
||||
// calculate message length
|
||||
const msgLen = writeUIntLE(new Uint8Array(8), msg.length, 0, 8);
|
||||
|
||||
// obtain root
|
||||
const root = zerokitRLN.getRoot(this.zkRLN);
|
||||
const rootsBytes = concatenate(...roots);
|
||||
|
||||
return zerokitRLN.verifyWithRoots(
|
||||
this.zkRLN,
|
||||
concatenate(pBytes, msgLen, msg),
|
||||
root
|
||||
rootsBytes
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ethers } from "ethers";
|
||||
|
||||
import { RLN_ABI } from "./constants.js";
|
||||
import { MembershipKey, RLNInstance } from "./rln.js";
|
||||
import { IdentityCredential, RLNInstance } from "./rln.js";
|
||||
|
||||
type Member = {
|
||||
pubkey: string;
|
||||
@ -94,20 +94,19 @@ export class RLNContract {
|
||||
rlnInstance: RLNInstance,
|
||||
signature: string
|
||||
): Promise<ethers.Event | undefined> {
|
||||
const membershipKey = await rlnInstance.generateSeededMembershipKey(
|
||||
signature
|
||||
);
|
||||
const identityCredential =
|
||||
await rlnInstance.generateSeededIdentityCredential(signature);
|
||||
|
||||
return this.registerWithKey(membershipKey);
|
||||
return this.registerWithKey(identityCredential);
|
||||
}
|
||||
|
||||
public async registerWithKey(
|
||||
membershipKey: MembershipKey
|
||||
credential: IdentityCredential
|
||||
): Promise<ethers.Event | undefined> {
|
||||
const depositValue = await this.contract.MEMBERSHIP_DEPOSIT();
|
||||
|
||||
const txRegisterResponse: ethers.ContractTransaction =
|
||||
await this.contract.register(membershipKey.IDCommitmentBigInt, {
|
||||
await this.contract.register(credential.IDCommitmentBigInt, {
|
||||
value: depositValue,
|
||||
});
|
||||
const txRegisterReceipt = await txRegisterResponse.wait();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user