diff --git a/README.md b/README.md index 54dff3c..d56f563 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Browser library providing the cryptographic functions for Waku RLN Relay https://rfc.vac.dev/spec/17/ ### Install + ``` npm install @waku/rln @@ -13,6 +14,7 @@ yarn add @waku/rln ``` ### Running example app + ``` git clone https://github.com/waku-org/js-rln @@ -26,10 +28,10 @@ npm start Browse http://localhost:8080 and open the dev tools console to see the proof being generated and its verification - ### Usage #### Initializing the library + ```js import * as rln from "@waku/rln"; @@ -37,45 +39,60 @@ const rlnInstance = wait rln.create(); ``` #### Generating RLN membership keypair + ```js let memKeys = rlnInstance.generateMembershipKey(); ``` +#### Generating RLN membership keypair using a seed + +```js +let memKeys = rlnInstance.generateSeededMembershipKey(seed); +``` #### Adding membership keys into merkle tree + ```js rlnInstance.insertMember(memKeys.IDCommitment); ``` #### Generating a proof + ```js // prepare the message -const uint8Msg = Uint8Array.from("Hello World".split("").map(x => x.charCodeAt())); +const uint8Msg = Uint8Array.from( + "Hello World".split("").map((x) => x.charCodeAt()) +); // setting up the epoch (With 0s for the test) const epoch = new Uint8Array(32); // generating a proof -const proof = await rlnInstance.generateProof(uint8Msg, index, epoch, memKeys.IDKey) +const proof = await rlnInstance.generateProof( + uint8Msg, + index, + epoch, + memKeys.IDKey +); ``` #### Verifying a proof + ```js try { - // verify the proof - const verificationResult = rlnInstance.verifyProof(proof); - console.log("Is proof verified?", verificationResult ? "yes" : "no"); + // verify the proof + const verificationResult = rlnInstance.verifyProof(proof); + console.log("Is proof verified?", verificationResult ? "yes" : "no"); } catch (err) { - console.log("Invalid proof") + console.log("Invalid proof"); } ``` - - ### Updating circuit, verification key and zkey + The RLN specs defines the defaults. These values are fixed and should not change. Currently, these [resources](https://github.com/vacp2p/zerokit/tree/master/rln/resources/tree_height_20) are being used. -If they change, this file needs to be updated in `resources.ts` which +If they change, this file needs to be updated in `resources.ts` which contains these values encoded in base64 in this format: ``` @@ -85,37 +102,41 @@ const zkey = "..."; export {verification_key, circuit, zkey}; ``` -A tool like GNU's `base64` could be used to encode this data. +A tool like GNU's `base64` could be used to encode this data. ### Updating zerokit + 1. Make sure you have nodejs installed and a C compiler 2. Install wasm-pack + ``` curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh ``` + 3. Compile RLN for wasm + ``` git clone https://github.com/vacp2p/zerokit cd zerokit/rln-wasm wasm-pack build --release ``` -4. Copy `pkg/rln*` into `src/zerokit` +4. Copy `pkg/rln*` into `src/zerokit` ## Bugs, Questions & Features If you encounter any bug or would like to propose new features, feel free to [open an issue](https://github.com/waku-org/js-rln/issues/new/). -For more general discussion, help and latest news, join [Vac Discord](https://discord.gg/PQFdubGt6d) or [Telegram](https://t.me/vacp2p). - +For more general discussion, help and latest news, join [Vac Discord](https://discord.gg/PQFdubGt6d) or [Telegram](https://t.me/vacp2p). ## License + Licensed and distributed under either of -* MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT +- MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT or -* Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0) +- Apache License, Version 2.0, ([LICENSE-APACHEv2](LICENSE-APACHEv2) or http://www.apache.org/licenses/LICENSE-2.0) at your option. These files may not be copied, modified, or distributed except according to those terms. diff --git a/package-lock.json b/package-lock.json index 183824c..6e02fc4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.12", "license": "MIT OR Apache-2.0", "dependencies": { - "@waku/zerokit-rln-wasm": "^0.0.4" + "@waku/zerokit-rln-wasm": "^0.0.5" }, "devDependencies": { "@rollup/plugin-commonjs": "^22.0.2", @@ -2549,9 +2549,9 @@ "dev": true }, "node_modules/@waku/zerokit-rln-wasm": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.4.tgz", - "integrity": "sha512-J5Dh3CQAvSk1cn6Pv61wbTwuB0Sc1gR53ljVFqAovvTQSmMxY3I8vjE2vml5dLlhVCIlSAfBfnOr/OaBD3b0Mg==" + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.5.tgz", + "integrity": "sha512-uZHZRk06WrnqJJOVwIIKtsjWf2d6g2JpK8FtC0lHg4JJkOxhJy0pgEIuBCPw8Je4MpF9FCtIO/ww7xicdlC2GA==" }, "node_modules/@web/rollup-plugin-import-meta-assets": { "version": "1.0.7", @@ -12981,9 +12981,9 @@ "dev": true }, "@waku/zerokit-rln-wasm": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.4.tgz", - "integrity": "sha512-J5Dh3CQAvSk1cn6Pv61wbTwuB0Sc1gR53ljVFqAovvTQSmMxY3I8vjE2vml5dLlhVCIlSAfBfnOr/OaBD3b0Mg==" + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.5.tgz", + "integrity": "sha512-uZHZRk06WrnqJJOVwIIKtsjWf2d6g2JpK8FtC0lHg4JJkOxhJy0pgEIuBCPw8Je4MpF9FCtIO/ww7xicdlC2GA==" }, "@web/rollup-plugin-import-meta-assets": { "version": "1.0.7", diff --git a/package.json b/package.json index 0b59d9e..2b1aedd 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,6 @@ ] }, "dependencies": { - "@waku/zerokit-rln-wasm": "^0.0.4" + "@waku/zerokit-rln-wasm": "^0.0.5" } } diff --git a/src/index.spec.ts b/src/index.spec.ts index 4c843da..9382764 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -58,4 +58,68 @@ describe("js-rln", () => { console.log(err); } }); + 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); + + //peer's index in the Merkle Tree + const index = 5; + + // Create a Merkle tree with random members + for (let i = 0; i < 10; i++) { + if (i == index) { + // insert the current peer's pk + rlnInstance.insertMember(memKeys.IDCommitment); + } else { + // create a new key pair + rlnInstance.insertMember( + rlnInstance.generateMembershipKey().IDCommitment + ); + } + } + + // prepare the message + const uint8Msg = Uint8Array.from( + "Hello World".split("").map((x) => x.charCodeAt(0)) + ); + + // setting up the epoch + const epoch = new Date(); + + // generating proof + const proof = await rlnInstance.generateRLNProof( + uint8Msg, + index, + epoch, + memKeys.IDKey + ); + + try { + // verify the proof + const verifResult = rlnInstance.verifyRLNProof(proof, uint8Msg); + expect(verifResult).to.be.true; + } catch (err) { + assert.fail(0, 1, "should not have failed proof verification"); + } + + try { + // Modifying the signal so it's invalid + uint8Msg[4] = 4; + // verify the proof + const verifResult = rlnInstance.verifyRLNProof(proof, uint8Msg); + expect(verifResult).to.be.false; + } catch (err) { + console.log(err); + } + }); + 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 memKeys = rlnInstance.generateSeededMembershipKey(seed); + const memKeys2 = rlnInstance.generateSeededMembershipKey(seed); + + expect(memKeys.IDCommitment).to.equal(memKeys2.IDCommitment); + expect(memKeys.IDKey).to.equal(memKeys2.IDKey); + }); }); diff --git a/src/rln.ts b/src/rln.ts index 0aee04b..ce31e86 100644 --- a/src/rln.ts +++ b/src/rln.ts @@ -125,6 +125,15 @@ export class RLNInstance { return MembershipKey.fromBytes(memKeys); } + generateSeededMembershipKey(seed: string): MembershipKey { + const seedBytes = stringEncoder.encode(seed); + const memKeys = zerokitRLN.generateSeededMembershipKey( + this.zkRLN, + seedBytes + ); + return MembershipKey.fromBytes(memKeys); + } + insertMember(idCommitment: Uint8Array): void { zerokitRLN.insertMember(this.zkRLN, idCommitment); }