diff --git a/packages/identity/package.json b/packages/identity/package.json index 21e0420..6cde86c 100644 --- a/packages/identity/package.json +++ b/packages/identity/package.json @@ -1,16 +1,11 @@ { "name": "@libsem/identity", - "version": "1.0.4", - "description": "work with zk identites", + "version": "1.0.5", + "description": "Library for managing identites for Semaphore and Rln protocols", "main": "dist/index.node.js", "types": "dist/types/index.d.ts", - "publishConfig": { - "access": "public" - }, - "exports": { - "import": "./dist/index.mjs", - "require": "./dist/index.node.js" - }, + "repository": "https://github.com/appliedzkp/libsemaphore", + "homepage": "https://github.com/appliedzkp/libsemaphore", "scripts": { "clean": "rimraf ./dist", "build:watch": "rollup -c rollup.config.ts -w", @@ -22,13 +17,19 @@ "email": "akinovak@gmail.com" }, "license": "MIT", - "homepage": "https://github.com/appliedzkp/libsemaphore", "dependencies": { "bigint-conversion": "^2.1.12", "circomlibjs": "^0.0.8", "crypto": "^1.0.1", "js-sha256": "^0.9.0" }, + "publishConfig": { + "access": "public" + }, + "exports": { + "import": "./dist/index.mjs", + "require": "./dist/index.node.js" + }, "devDependencies": { "@libsem/types": "../types", "rimraf": "^3.0.2", diff --git a/packages/protocols/package.json b/packages/protocols/package.json index 7acacf3..7543620 100644 --- a/packages/protocols/package.json +++ b/packages/protocols/package.json @@ -1,12 +1,11 @@ { "name": "@libsem/protocols", - "version": "1.0.4", - "description": "", + "version": "1.0.5", + "description": "Client library for generating and verifying Semaphore & Rln ZK proofs", "main": "dist/index.node.js", "types": "dist/types/index.d.ts", - "publishConfig": { - "access": "public" - }, + "repository": "https://github.com/appliedzkp/libsemaphore", + "homepage": "https://github.com/appliedzkp/libsemaphore", "exports": { "import": "./dist/index.mjs", "require": "./dist/index.node.js" @@ -20,8 +19,10 @@ "name": "Andrija Novakovic", "email": "akinovak@gmail.com" }, - "homepage": "https://github.com/appliedzkp/libsemaphore/protocols", "license": "MIT", + "publishConfig": { + "access": "public" + }, "dependencies": { "circomlibjs": "^0.0.8", "ethers": "^5.4.7", diff --git a/packages/protocols/src/nRln.ts b/packages/protocols/src/nRln.ts index 78eb4d4..440a121 100644 --- a/packages/protocols/src/nRln.ts +++ b/packages/protocols/src/nRln.ts @@ -1,12 +1,20 @@ import { ZkProtocol } from "./zk-protocol"; import { genSignalHash, poseidonHash } from "./utils"; import { Fq } from "./utils"; -import { Identity } from "@libsem/types"; class NRln extends ZkProtocol { - genWitness(identity: Identity, merkleProof: any, epoch: string | bigint, signal: string, shouldHash = true): any { + /** + * Creates witness for nrln proof + * @param identitySecret identity secret + * @param merkleProof merkle proof that identity exists in nrln tree + * @param epoch epoch on which signal is broadcasted + * @param signal signal that is being broadcasted + * @param shouldHash should signal be hashed before broadcast + * @returns rln witness + */ + genWitness(identitySecret: Array, merkleProof: any, epoch: string | bigint, signal: string, shouldHash = true): any { return { - identity_secret: [identity.identityTrapdoor, identity.identityNullifier], + identity_secret: identitySecret, path_elements: merkleProof.pathElements, identity_path_index: merkleProof.indices, x: shouldHash ? genSignalHash(signal) : signal, @@ -14,7 +22,14 @@ class NRln extends ZkProtocol { }; } - //TODO add rln identifier + /** + * + * @param identitySecret identity secret + * @param epoch epoch + * @param x singal hash + * @param limit number of messages per epoch allowed + * @returns + */ calculateOutput(identitySecret: Array, epoch: bigint, x: bigint, limit: number): Array { const a0 = poseidonHash(identitySecret); @@ -35,10 +50,21 @@ class NRln extends ZkProtocol { return [y, nullifier]; } + /** + * Calculates slashing nullifier + * @param coeffs coeefitients from calculated polinomial + * @returns slashing nullifier + */ genNullifier(coeffs: Array): bigint { return poseidonHash(coeffs); } + /** + * When spam occurs, identity secret can be retrieved + * @param xs + * @param ys + * @returns identity secret + */ retrieveSecret(xs: Array, ys: Array): bigint { if (xs.length !== ys.length) throw new Error("x and y arrays must be of same size"); const numOfPoints: number = xs.length; diff --git a/packages/protocols/src/rln.ts b/packages/protocols/src/rln.ts index d61e63e..131b065 100644 --- a/packages/protocols/src/rln.ts +++ b/packages/protocols/src/rln.ts @@ -4,6 +4,17 @@ import { Fq } from "./utils"; class Rln extends ZkProtocol { + + /** + * Creates witness for rln proof + * @param identitySecret identity secret + * @param merkleProof merkle proof that identity exists in rln tree + * @param epoch epoch on which signal is broadcasted + * @param signal signal that is being broadcasted + * @param rlnIdentifier unique identifier of rln dapp + * @param shouldHash should signal be hashed before broadcast + * @returns rln witness + */ genWitness(identitySecret: bigint, merkleProof: any, epoch: string | bigint, signal: string, rlnIdentifier: bigint, shouldHash = true): any { return { identity_secret: identitySecret, @@ -15,6 +26,14 @@ class Rln extends ZkProtocol { } } + /** + * Calculates + * @param identitySecret identity secret + * @param epoch epoch on which signal is broadcasted + * @param rlnIdentifier unique identifier of rln dapp + * @param x signal hash + * @returns y & slashing nullfier + */ calculateOutput(identitySecret: bigint, epoch: string, rlnIdentifier: bigint, x: bigint): Array { const a1: bigint = poseidonHash([identitySecret, BigInt(epoch), rlnIdentifier]); const y: bigint = Fq.normalize(a1 * x + identitySecret); @@ -22,20 +41,39 @@ class Rln extends ZkProtocol { return [y, nullifier] } + /** + * + * @param a1 y = a1 * x + a0 (a1 = poseidonHash(identity secret, epoch, rlnIdentifier)) + * @param rlnIdentifier unique identifier of rln dapp + * @returns rln slashing nullifier + */ genNullifier(a1: bigint, rlnIdentifier: bigint): bigint { return poseidonHash([a1, rlnIdentifier]); } + /** + * When spam occurs, identity secret can be retrieved + * @param x1 x1 + * @param x2 x2 + * @param y1 y1 + * @param y2 y2 + * @returns identity secret + */ retrieveSecret(x1: bigint, x2:bigint, y1:bigint, y2:bigint): bigint { const slope = Fq.div(Fq.sub(y2, y1), Fq.sub(x2, x1)) const privateKey = Fq.sub(y1, Fq.mul(slope, x1)); return Fq.normalize(privateKey); } + /** + * + * @returns unique identifier of rln dapp + */ + genIdentifier(): bigint { return Fq.random(); } } -export default new Rln(); \ No newline at end of file +export default new Rln(); diff --git a/packages/protocols/src/semaphore.ts b/packages/protocols/src/semaphore.ts index 628a14b..dfba136 100644 --- a/packages/protocols/src/semaphore.ts +++ b/packages/protocols/src/semaphore.ts @@ -3,6 +3,15 @@ import { genSignalHash, poseidonHash } from "./utils"; import { Identity, MerkleProof } from "@libsem/types"; class Semaphore extends ZkProtocol { + /** + * Creates witness for semaphore proof + * @param identity semaphore identity + * @param merkleProof merkle proof that identity exists in semaphore tree + * @param externalNullifier topic on which vote should be broadcasted + * @param signal signal that should be broadcasted + * @param shouldHash should signal be hashed before broadcast + * @returns + */ genWitness( identity: Identity, merkleProof: MerkleProof, @@ -20,6 +29,13 @@ class Semaphore extends ZkProtocol { }; } + /** + * generates nullifier hash for semaphore proof + * @param externalNullifier external nullifier + * @param identityNullifier identity nullifier + * @param nLevels depth of tree + * @returns + */ genNullifierHash(externalNullifier: string | bigint, identityNullifier: string | bigint, nLevels: number): bigint { return poseidonHash([BigInt(externalNullifier), BigInt(identityNullifier), BigInt(nLevels)]); } diff --git a/packages/protocols/src/utils.ts b/packages/protocols/src/utils.ts index c1013c2..5266dcd 100644 --- a/packages/protocols/src/utils.ts +++ b/packages/protocols/src/utils.ts @@ -36,6 +36,15 @@ export const createTree = (depth: number, zeroValue: number | BigInt, leavesPerN return new Tree.IncrementalQuinTree(depth, zeroValue, leavesPerNode, poseidonHash); }; +/** + * Creates merkle proof + * @param depth depth of tree + * @param zeroValue zero value of tree + * @param leavesPerNode number of leaves to derive hash from + * @param leaves leaves to build try from + * @param leaf leaf for which merkle proof should be generated + * @returns merkle proof + */ export const generateMerkleProof = ( depth: number, zeroValue: number | BigInt, diff --git a/packages/protocols/src/zk-protocol.ts b/packages/protocols/src/zk-protocol.ts index d92749a..764f9eb 100644 --- a/packages/protocols/src/zk-protocol.ts +++ b/packages/protocols/src/zk-protocol.ts @@ -4,15 +4,33 @@ import { SNARK_FIELD_SIZE } from "./utils"; import { IProof } from "@libsem/types"; export class ZkProtocol { + /** + * Generates full proof + * @param grothInput witness + * @param wasmFilePath path to wasm file + * @param finalZkeyPath path to final zkey file + * @returns zero knowledge proof + */ genProof(grothInput: any, wasmFilePath: string, finalZkeyPath: string): Promise { return groth16.fullProve(grothInput, wasmFilePath, finalZkeyPath); } + /** + * Verify ZK proof + * @param vKey verifikation key + * @param fullProof proof + * @returns Is provided proof valid + */ verifyProof(vKey: string, fullProof: IProof): Promise { const { proof, publicSignals } = fullProof; return groth16.verify(vKey, publicSignals, proof); } + /** + * Transforms proof that can be compatible with solidity input + * @param fullProof + * @returns Proof + */ packToSolidityProof(fullProof: IProof) { const { proof, publicSignals } = fullProof;