diff --git a/packages/identity/package.json b/packages/identity/package.json index bbaae78..78b80c6 100644 --- a/packages/identity/package.json +++ b/packages/identity/package.json @@ -1,6 +1,6 @@ { "name": "@libsem/identity", - "version": "1.0.19", + "version": "1.0.20", "description": "Library for managing identites for Semaphore and Rln protocols.", "main": "dist/index.node.js", "types": "dist/types/index.d.ts", diff --git a/packages/identity/src/identity.ts b/packages/identity/src/identity.ts index 8486883..733fa11 100644 --- a/packages/identity/src/identity.ts +++ b/packages/identity/src/identity.ts @@ -2,6 +2,7 @@ import { genRandomIdentity, genIdentityFromMessage, genRandomNumber } from "./st import * as bigintConversion from "bigint-conversion" import * as ciromlibjs from "circomlibjs" import { Identity, SerializedIdentity } from "@libsem/types" +import {Fq} from "./utils" const poseidonHash = (data: Array): bigint => { return ciromlibjs.poseidon(data) @@ -14,9 +15,9 @@ export enum Strategy { } class ZkIdentity { - private identityTrapdoor: bigint - private identityNullifier: bigint - private secret: Array = [] + private identityTrapdoor: bigint; + private identityNullifier: bigint; + private secret: Array = []; /** * Generates new ZkIdentity * @param strategy strategy for identity generation @@ -28,10 +29,12 @@ class ZkIdentity { const { identityTrapdoor, identityNullifier } = genRandomIdentity() this.identityTrapdoor = identityTrapdoor this.identityNullifier = identityNullifier + this.genSecret() } else if (strategy === Strategy.MESSAGE) { const { identityTrapdoor, identityNullifier } = genIdentityFromMessage(metadata as string) this.identityTrapdoor = identityTrapdoor this.identityNullifier = identityNullifier + this.genSecret() } else if (strategy === Strategy.SERIALIZED) { const { identityNullifier, identityTrapdoor, secret } = metadata as SerializedIdentity this.identityNullifier = bigintConversion.hexToBigint(identityNullifier) @@ -75,42 +78,35 @@ class ZkIdentity { return this.secret } + + getSecretHash(): bigint { + return poseidonHash(this.secret) + } + + /** * Creates secret from ZkIdentity * @returns */ - genSecretFromIdentity() { - this.secret = [this.identityNullifier, this.identityTrapdoor] - } - - /** - * Creates random secret - * @param parts number of parts in secret - * @returns secret - */ - genRandomSecret(parts = 2) { - this.secret = [] - for (let i = 0; i < parts; i++) { - this.secret.push(genRandomNumber()) + genSecret(parts: number = 2): void { + if(parts < 2) throw new Error("Invalid number of parts"); + if(parts === 2) { + this.secret = [this.identityNullifier, this.identityTrapdoor] + } else { + let initialComponent = Fq.pow(this.identityNullifier, this.identityTrapdoor); + this.secret = [initialComponent] + for(let i = 1; i < parts; i++) { + this.secret.push(Fq.pow(initialComponent, BigInt(i + 1))) + } } } - /** - * Generate commitment from identity secret - * @returns identity commitment - */ - genIdentityCommitmentFromSecret(): bigint { - if (!this.secret.length) throw new Error("Secret is not generated") - const secretHash = poseidonHash(this.secret) - return poseidonHash([secretHash]) - } - /** * Generate commitment from identity * @returns identity commitment */ genIdentityCommitment(): bigint { - const secretHash = poseidonHash([this.identityNullifier, this.identityTrapdoor]) + const secretHash = this.getSecretHash(); return poseidonHash([secretHash]) } diff --git a/packages/identity/src/utils.ts b/packages/identity/src/utils.ts new file mode 100644 index 0000000..9b9c217 --- /dev/null +++ b/packages/identity/src/utils.ts @@ -0,0 +1,4 @@ +export const SNARK_FIELD_SIZE = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617") + +const ZqField = require("ffjavascript").ZqField +export const Fq = new ZqField(SNARK_FIELD_SIZE) \ No newline at end of file diff --git a/packages/identity/tests/identity.test.ts b/packages/identity/tests/identity.test.ts index 6f04e92..484e55e 100644 --- a/packages/identity/tests/identity.test.ts +++ b/packages/identity/tests/identity.test.ts @@ -16,17 +16,17 @@ describe("Semaphore identity", () => { it("Should generate secret from identity", async () => { const identity: ZkIdentity = new ZkIdentity() - identity.genSecretFromIdentity() + identity.genSecret() const identitySecret = identity.getSecret() expect(identitySecret.length).toEqual(2) expect(typeof identitySecret).toEqual("object") }) - it("Should generate random secret", async () => { + it("Should generate multipart secret", async () => { const secretParts = 5 const identity: ZkIdentity = new ZkIdentity() - identity.genRandomSecret(secretParts) + identity.genSecret(secretParts) const identitySecret = identity.getSecret() expect(identitySecret.length).toEqual(5) @@ -35,20 +35,12 @@ describe("Semaphore identity", () => { it("Should generate identity commitment from identity", async () => { const identity: ZkIdentity = new ZkIdentity() + identity.genSecret(); const identityCommitment: bigint = identity.genIdentityCommitment() expect(typeof identityCommitment).toEqual("bigint") }) - it("Should generate identity commitment from random secret", async () => { - const secretParts = 5 - const identity: ZkIdentity = new ZkIdentity() - identity.genRandomSecret(secretParts) - const identityCommitment: bigint = identity.genIdentityCommitmentFromSecret() - - expect(typeof identityCommitment).toEqual("bigint") - }) - it("Should serialize identity", async () => { const identity: ZkIdentity = new ZkIdentity() const serialized: string = identity.serializeIdentity() diff --git a/packages/protocols/package.json b/packages/protocols/package.json index d775e82..9b6ff0f 100644 --- a/packages/protocols/package.json +++ b/packages/protocols/package.json @@ -1,6 +1,6 @@ { "name": "@libsem/protocols", - "version": "1.0.25", + "version": "1.0.26", "description": "Client library for generating and verifying Semaphore & Rln ZK proofs.", "main": "dist/index.node.js", "types": "dist/types/index.d.ts", diff --git a/packages/protocols/src/index.ts b/packages/protocols/src/index.ts index abee43f..b15c78b 100644 --- a/packages/protocols/src/index.ts +++ b/packages/protocols/src/index.ts @@ -1,7 +1,7 @@ import Semaphore from "./semaphore" import Rln from "./rln" import NRln from "./nRln" -import { generateMerkleProof, genExternalNullifier, genSignalHash } from "./utils" +import { generateMerkleProof, genExternalNullifier, genSignalHash, Fq } from "./utils" import { Identity, MerkleProof, FullProof } from "@libsem/types" export { Semaphore, Rln, NRln, generateMerkleProof, genExternalNullifier, genSignalHash, Identity, MerkleProof, FullProof } diff --git a/packages/protocols/tests/nrln.test.ts b/packages/protocols/tests/nrln.test.ts index aa01b91..432b095 100644 --- a/packages/protocols/tests/nrln.test.ts +++ b/packages/protocols/tests/nrln.test.ts @@ -13,8 +13,8 @@ beforeAll(() => { for (let i = 0; i < leafIndex; i++) { const tmpIdentity = new ZkIdentity(); - tmpIdentity.genRandomSecret(SPAM_TRESHOLD); - const tmpCommitment: bigint = tmpIdentity.genIdentityCommitmentFromSecret(); + tmpIdentity.genSecret(SPAM_TRESHOLD); + const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment(); identityCommitments.push(tmpCommitment) } }) @@ -23,9 +23,9 @@ describe("NRln", () => { describe("NRln functionalities", () => { it("Generate nrln witness", () => { const identity: ZkIdentity = new ZkIdentity(); - identity.genRandomSecret(SPAM_TRESHOLD); + identity.genSecret(SPAM_TRESHOLD); - const identityCommitment: bigint = identity.genIdentityCommitmentFromSecret(); + const identityCommitment: bigint = identity.genIdentityCommitment(); const identitySecret: bigint[] = identity.getSecret(); const commitments: Array = Object.assign([], identityCommitments) @@ -35,19 +35,19 @@ describe("NRln", () => { const epoch: string = genExternalNullifier("test-epoch") const rlnIdentifier: bigint = NRln.genIdentifier() - const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 5, commitments, identityCommitment) + const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment) const witness: FullProof = NRln.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier) expect(typeof witness).toBe("object") }) - it.skip("Generate nrln proof and verify it", async () => { + it("Generate nrln proof and verify it", async () => { /** * Compiled NRln circuits are needed to run this test so it's being skipped in hooks */ const identity: ZkIdentity = new ZkIdentity(); - identity.genRandomSecret(SPAM_TRESHOLD); + identity.genSecret(SPAM_TRESHOLD); - const identityCommitment: bigint = identity.genIdentityCommitmentFromSecret(); + const identityCommitment: bigint = identity.genIdentityCommitment(); const identitySecret: bigint[] = identity.getSecret(); const commitments: Array = Object.assign([], identityCommitments) @@ -77,7 +77,7 @@ describe("NRln", () => { }, 30000) it("Should retrieve user secret after spaming", () => { const identity: ZkIdentity = new ZkIdentity(); - identity.genRandomSecret(SPAM_TRESHOLD); + identity.genSecret(SPAM_TRESHOLD); const identitySecret: bigint[] = identity.getSecret(); diff --git a/packages/protocols/tests/rln.test.ts b/packages/protocols/tests/rln.test.ts index 3e65509..7339079 100644 --- a/packages/protocols/tests/rln.test.ts +++ b/packages/protocols/tests/rln.test.ts @@ -21,7 +21,6 @@ describe("Rln", () => { describe("Rln functionalities", () => { it("Generate rln witness", () => { const identity: ZkIdentity = new ZkIdentity(); - identity.genSecretFromIdentity(); const identityCommitment: bigint = identity.genIdentityCommitment(); const secretHash: bigint = poseidonHash(identity.getSecret()); @@ -37,12 +36,11 @@ describe("Rln", () => { expect(typeof witness).toBe("object") }) - it.skip("Generate rln proof and verify it", async () => { + it("Generate rln proof and verify it", async () => { /** * Compiled RLN circuits are needed to run this test so it's being skipped in hooks */ const identity: ZkIdentity = new ZkIdentity(); - identity.genSecretFromIdentity(); const secretHash: bigint = poseidonHash(identity.getSecret()); const identityCommitment: bigint = identity.genIdentityCommitment(); @@ -74,7 +72,6 @@ describe("Rln", () => { }, 30000) it("Should retrieve user secret after spaming", () => { const identity: ZkIdentity = new ZkIdentity(); - identity.genSecretFromIdentity(); const secretHash: bigint = poseidonHash(identity.getSecret()); const signal1 = "hey hey" diff --git a/packages/protocols/tests/semaphore.test.ts b/packages/protocols/tests/semaphore.test.ts index 013957f..dd2b26e 100644 --- a/packages/protocols/tests/semaphore.test.ts +++ b/packages/protocols/tests/semaphore.test.ts @@ -36,7 +36,7 @@ describe("Semaphore", () => { expect(typeof witness).toBe("object") }) - it.skip("Should generate semaphore full proof", async () => { + it("Should generate semaphore full proof", async () => { /** * Compiled semaphore circuits are needed to run this test, so it's being skipped in hooks */