fix: rln/nrln refactoring, identities and types update, zkeyFiles added

Former-commit-id: 69221053bfd42ca787e405b90b7654a6320eb797 [formerly b32fc77aa40f6306e415d41807cd2582add75576] [formerly fa913c98a96f91c77d01df6725d77adb020b68aa [formerly 36fcf8482b]]
Former-commit-id: 38c46f3594790895f456019d533aa41b3d01ca31 [formerly a204a646b8d4194514d68dd922183bbecfefdffa]
Former-commit-id: d980f64fdcb24cf04c129818c19d7895605f156e
This commit is contained in:
bdim1
2021-12-28 16:28:26 +01:00
parent 5945d892ce
commit b61a381a11
13 changed files with 227 additions and 272 deletions

View File

@@ -18,7 +18,7 @@
},
"license": "MIT",
"dependencies": {
"@libsem/types": "^1.0.7",
"@libsem/types": "^1.0.8",
"bigint-conversion": "^2.1.12",
"circomlibjs": "^0.0.8",
"crypto": "^1.0.1",

View File

@@ -14,10 +14,16 @@ export enum Strategy {
SERIALIZED
}
export enum SecretType {
GENERIC, // generic secret, composed of identityNullifier and identityTrapdoor
MULTIPART_SECRET, // multipart secret, composed from multiple parts dependent on the spam threshold
}
class ZkIdentity {
private identityTrapdoor: bigint;
private identityNullifier: bigint;
private secret: Array<bigint> = [];
private multipartSecret: Array<bigint> = [];
/**
* Generates new ZkIdentity
* @param strategy strategy for identity generation
@@ -30,86 +36,65 @@ class ZkIdentity {
this.identityTrapdoor = identityTrapdoor
this.identityNullifier = identityNullifier
this.genSecret()
this.genMultipartSecret()
} else if (strategy === Strategy.MESSAGE) {
const { identityTrapdoor, identityNullifier } = genIdentityFromMessage(metadata as string)
this.identityTrapdoor = identityTrapdoor
this.identityNullifier = identityNullifier
this.genSecret()
this.genMultipartSecret()
} else if (strategy === Strategy.SERIALIZED) {
const { identityNullifier, identityTrapdoor, secret } = metadata as SerializedIdentity
const { identityNullifier, identityTrapdoor, secret, multipartSecret } = metadata as SerializedIdentity
this.identityNullifier = bigintConversion.hexToBigint(identityNullifier)
this.identityTrapdoor = bigintConversion.hexToBigint(identityTrapdoor)
this.secret = secret.map(item => bigintConversion.hexToBigint(item));
this.multipartSecret = multipartSecret.map(item => bigintConversion.hexToBigint(item));
} else throw new Error("provided strategy is not supported")
}
/**
* Unserialize serialized identity
* @param serialisedIdentity
* @returns
*/
static genFromSerialized(serialisedIdentity: string): ZkIdentity {
const data = JSON.parse(serialisedIdentity)
if(!('identityNullifier' in data) || !('identityTrapdoor' in data) || !('secret' in data)) throw new Error("Wrong input identity");
return new ZkIdentity(Strategy.SERIALIZED, {
identityNullifier: data['identityNullifier'],
identityTrapdoor: data['identityTrapdoor'],
secret: data['secret']
})
}
/**
*
* @returns Identity
*/
getIdentity(): Identity {
return {
identityNullifier: this.identityNullifier,
identityTrapdoor: this.identityTrapdoor
}
}
getNullifier(): bigint {
return this.identityNullifier
}
getSecret(): Array<bigint> {
return this.secret
}
getSecretHash(): bigint {
return poseidonHash(this.secret)
}
// Secret and identity generation
/**
* Creates secret from ZkIdentity
* @returns
* Generate generic secret. To be used by Semaphore related apps.
*/
genSecret(parts = 2): void {
genSecret(): void {
this.secret = [this.identityNullifier, this.identityTrapdoor]
}
/**
* Generate multipart secret. To be used by RLN related apps.
* @param parts The number of parts that the secret should be composed of,
* corresponding to the spam threshold of the protocol
*/
genMultipartSecret(parts = 2): void {
if(parts < 2) throw new Error("Invalid number of parts");
if(parts === 2) {
this.secret = [this.identityNullifier, this.identityTrapdoor]
} else {
const initialComponent = Fq.pow(this.identityTrapdoor, this.identityNullifier);
this.secret = [initialComponent]
for(let i = 1; i < parts; i++) {
this.secret.push(Fq.pow(initialComponent, BigInt(i + 1)))
}
const initialComponent = Fq.pow(this.identityTrapdoor, this.identityNullifier);
this.multipartSecret = [initialComponent]
for(let i = 1; i < parts; i++) {
this.multipartSecret.push(Fq.pow(initialComponent, BigInt(i + 1)))
}
}
/**
* Generate commitment from identity
* Generate commitment from secret
* @param secretType The secret type for which to generate identity commitment
* @returns identity commitment
*/
genIdentityCommitment(): bigint {
const secretHash = this.getSecretHash();
genIdentityCommitment(secretType: SecretType = SecretType.GENERIC): bigint {
let secretHash = this.getSecretHash();
if(secretType === SecretType.MULTIPART_SECRET) {
secretHash = this.getMultipartSecretHash();
}
return poseidonHash([secretHash])
}
// Serialization
/**
* Serializes the `identityNullifier`, `identityTrapdoor` and `secret` from the identity
* @returns stringified serialized identity
@@ -118,10 +103,61 @@ class ZkIdentity {
const data: SerializedIdentity = {
identityNullifier: this.identityNullifier.toString(16),
identityTrapdoor: this.identityTrapdoor.toString(16),
secret: this.secret.map(item => item.toString(16))
secret: this.secret.map(item => item.toString(16)),
multipartSecret: this.multipartSecret.map(item => item.toString(16))
}
return JSON.stringify(data);
}
/**
* Unserialize serialized identity
* @param serialisedIdentity
* @returns
*/
static genFromSerialized(serialisedIdentity: string): ZkIdentity {
const data = JSON.parse(serialisedIdentity)
if(!('identityNullifier' in data) || !('identityTrapdoor' in data) || !('secret' in data) || !('multipartSecret' in data)) throw new Error("Wrong input identity");
return new ZkIdentity(Strategy.SERIALIZED, {
identityNullifier: data['identityNullifier'],
identityTrapdoor: data['identityTrapdoor'],
secret: data['secret'],
multipartSecret: data['multipartSecret']
})
}
// Getters
/**
* Return the raw user identity, composed of identityNullifier and identityTrapdoor.
* @returns Identity
*/
getIdentity(): Identity {
return {
identityNullifier: this.identityNullifier,
identityTrapdoor: this.identityTrapdoor
}
}
getNullifier(): bigint {
return this.identityNullifier
}
getSecret(): Array<bigint> {
return this.secret
}
getMultipartSecret(): Array<bigint> {
return this.multipartSecret
}
getSecretHash(): bigint {
return poseidonHash(this.secret)
}
getMultipartSecretHash(): bigint {
return poseidonHash(this.multipartSecret);
}
}
export default ZkIdentity

View File

@@ -1,4 +1,4 @@
import ZkIdentity, { Strategy } from "./identity"
import ZkIdentity, { Strategy, SecretType } from "./identity"
import { Identity } from "@libsem/types"
export { ZkIdentity, Identity, Strategy }
export { ZkIdentity, Identity, Strategy, SecretType }

View File

@@ -26,8 +26,8 @@ describe("Semaphore identity", () => {
it("Should generate multipart secret", async () => {
const secretParts = 5
const identity: ZkIdentity = new ZkIdentity()
identity.genSecret(secretParts)
const identitySecret = identity.getSecret()
identity.genMultipartSecret(secretParts)
const identitySecret = identity.getMultipartSecret()
expect(identitySecret.length).toEqual(5)
expect(typeof identitySecret).toEqual("object")
@@ -35,7 +35,6 @@ 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")

View File

@@ -24,7 +24,7 @@
"access": "public"
},
"dependencies": {
"@libsem/types": "^1.0.7",
"@libsem/types": "^1.0.8",
"circomlibjs": "^0.0.8",
"ethers": "^5.4.7",
"incrementalquintree": "^1.0.7",

View File

@@ -1,7 +1,6 @@
import Semaphore from "./semaphore"
import Rln from "./rln"
import NRln from "./nRln"
import RLN from "./rln"
import { generateMerkleProof, genExternalNullifier, genSignalHash, Fq } from "./utils"
import { Identity, MerkleProof, FullProof } from "@libsem/types"
export { Semaphore, Rln, NRln, generateMerkleProof, genExternalNullifier, genSignalHash, Identity, MerkleProof, FullProof }
export { Semaphore, RLN, generateMerkleProof, genExternalNullifier, genSignalHash, Identity, MerkleProof, FullProof }

View File

@@ -1,104 +0,0 @@
import { ZkProtocol } from "./zk-protocol"
import { genSignalHash, poseidonHash } from "./utils"
import { Fq } from "./utils"
class NRln extends ZkProtocol {
/**
* 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 rlnIdentifier identifier used by each separate app, needed for more accurate spam filtering
* @param shouldHash should signal be hashed before broadcast
* @returns rln witness
*/
genWitness(
identitySecret: Array<bigint>,
merkleProof: any,
epoch: string | bigint,
signal: string,
rlnIdentifier: bigint,
shouldHash = true
): any {
return {
identity_secret: identitySecret,
path_elements: merkleProof.pathElements,
identity_path_index: merkleProof.indices,
x: shouldHash ? genSignalHash(signal) : signal,
epoch,
rln_identifier: rlnIdentifier
}
}
/**
*
* @param identitySecret identity secret
* @param epoch epoch
* @param x singal hash
* @param limit number of messages per epoch allowed
* @param rlnIdentifier identifier used by each separate app, needed for more accurate spam filtering
* @returns
*/
calculateOutput(identitySecret: Array<bigint>, epoch: bigint, x: bigint, limit: number, rlnIdentifier: bigint): Array<bigint> {
const a0 = poseidonHash(identitySecret)
const coeffs: Array<bigint> = []
let tmpX = x
coeffs.push(poseidonHash([identitySecret[0], epoch]))
let y: bigint = Fq.add(Fq.mul(coeffs[0], tmpX), a0)
for (let i = 1; i < limit; i++) {
tmpX = Fq.mul(x, tmpX)
coeffs.push(poseidonHash([identitySecret[i], epoch]))
y = Fq.add(y, Fq.mul(coeffs[i], tmpX))
}
coeffs.push(poseidonHash([rlnIdentifier]));
const nullifier: bigint = this.genNullifier(coeffs)
return [y, nullifier]
}
/**
* Calculates slashing nullifier
* @param coeffs coeefitients from calculated polinomial
* @returns slashing nullifier
*/
genNullifier(coeffs: Array<bigint>): bigint {
return poseidonHash(coeffs)
}
/**
* When spam occurs, identity secret can be retrieved
* @param xs
* @param ys
* @returns identity secret
*/
retrieveSecret(xs: Array<bigint>, ys: Array<bigint>): bigint {
if (xs.length !== ys.length) throw new Error("x and y arrays must be of same size")
const numOfPoints: number = xs.length
let f0 = BigInt(0)
for (let i = 0; i < numOfPoints; i++) {
let p = BigInt(1)
for (let j = 0; j < numOfPoints; j++) {
if (j !== i) {
p = Fq.mul(p, Fq.div(xs[j], Fq.sub(xs[j], xs[i])))
}
}
f0 = Fq.add(f0, Fq.mul(ys[i], p))
}
return f0
}
/**
*
* @returns unique identifier of the rln dapp
*/
genIdentifier(): bigint {
return Fq.random()
}
}
export default new NRln()

View File

@@ -2,19 +2,19 @@ import { ZkProtocol } from "./zk-protocol"
import { genSignalHash, poseidonHash } from "./utils"
import { Fq } from "./utils"
class Rln extends ZkProtocol {
class RLN extends ZkProtocol {
/**
* Creates witness for rln proof
* Creates witness for RLN proof
* @param identitySecret identity secret
* @param merkleProof merkle proof that identity exists in rln tree
* @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 rlnIdentifier identifier used by each separate app, needed for more accurate spam filtering
* @param shouldHash should signal be hashed before broadcast
* @returns rln witness
*/
genWitness(
identitySecret: bigint,
identitySecret: Array<bigint>,
merkleProof: any,
epoch: string | bigint,
signal: string,
@@ -32,51 +32,73 @@ 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
* @param epoch epoch
* @param x singal hash
* @param limit number of messages per epoch allowed
* @param rlnIdentifier identifier used by each separate app, needed for more accurate spam filtering
* @returns
*/
calculateOutput(identitySecret: bigint, epoch: bigint, rlnIdentifier: bigint, x: bigint): Array<bigint> {
const a1: bigint = poseidonHash([identitySecret, epoch])
const y: bigint = Fq.normalize(a1 * x + identitySecret)
const nullifier = this.genNullifier(a1, rlnIdentifier)
calculateOutput(identitySecret: Array<bigint>, epoch: bigint, x: bigint, limit: number, rlnIdentifier: bigint): Array<bigint> {
const a0 = poseidonHash(identitySecret)
const coeffs: Array<bigint> = []
let tmpX = x
coeffs.push(poseidonHash([identitySecret[0], epoch]))
let y: bigint = Fq.add(Fq.mul(coeffs[0], tmpX), a0)
for (let i = 1; i < limit; i++) {
tmpX = Fq.mul(x, tmpX)
coeffs.push(poseidonHash([identitySecret[i], epoch]))
y = Fq.add(y, Fq.mul(coeffs[i], tmpX))
}
coeffs.push(poseidonHash([rlnIdentifier]));
const nullifier: bigint = this.genNullifier(coeffs)
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
* Calculates slashing nullifier
* @param coeffs coeefitients from calculated polinomial
* @returns slashing nullifier
*/
genNullifier(a1: bigint, rlnIdentifier: bigint): bigint {
return poseidonHash([a1, rlnIdentifier])
genNullifier(coeffs: Array<bigint>): bigint {
return poseidonHash(coeffs)
}
/**
* When spam occurs, identity secret can be retrieved
* @param x1 x1
* @param x2 x2
* @param y1 y1
* @param y2 y2
* @param xs
* @param ys
* @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)
retrieveSecret(xs: Array<bigint>, ys: Array<bigint>): bigint {
if (xs.length !== ys.length) throw new Error("x and y arrays must be of same size")
const numOfPoints: number = xs.length
let f0 = BigInt(0)
for (let i = 0; i < numOfPoints; i++) {
let p = BigInt(1)
for (let j = 0; j < numOfPoints; j++) {
if (j !== i) {
p = Fq.mul(p, Fq.div(xs[j], Fq.sub(xs[j], xs[i])))
}
}
f0 = Fq.add(f0, Fq.mul(ys[i], p))
}
return f0
}
/**
*
* @returns unique identifier of the rln dapp
*/
genIdentifier(): bigint {
return Fq.random()
}
genIdentifier(): bigint {
return Fq.random()
}
}
export default new Rln()
export default new RLN()

View File

@@ -1,5 +1,5 @@
import { NRln } from "../src"
import { ZkIdentity } from "../../identity/src"
import { RLN } from "../src"
import { ZkIdentity, SecretType } from "../../identity/src"
import { MerkleProof, FullProof } from "../../types"
import { genSignalHash, genExternalNullifier, generateMerkleProof, poseidonHash } from "../src/utils"
import * as path from "path"
@@ -13,42 +13,42 @@ beforeAll(() => {
for (let i = 0; i < leafIndex; i++) {
const tmpIdentity = new ZkIdentity();
tmpIdentity.genSecret(SPAM_TRESHOLD);
const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment();
tmpIdentity.genMultipartSecret(SPAM_TRESHOLD);
const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment(SecretType.MULTIPART_SECRET);
identityCommitments.push(tmpCommitment)
}
})
describe("NRln", () => {
describe("NRln functionalities", () => {
it("Generate nrln witness", () => {
describe("RLN with non default spam threshold", () => {
describe("RLN features", () => {
it("Generate RLN witness", () => {
const identity: ZkIdentity = new ZkIdentity();
identity.genSecret(SPAM_TRESHOLD);
identity.genMultipartSecret(SPAM_TRESHOLD);
const identityCommitment: bigint = identity.genIdentityCommitment();
const identitySecret: bigint[] = identity.getSecret();
const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART_SECRET);
const identitySecret: bigint[] = identity.getMultipartSecret();
const commitments: Array<bigint> = Object.assign([], identityCommitments)
commitments.push(identityCommitment)
const signal = "hey hey"
const epoch: string = genExternalNullifier("test-epoch")
const rlnIdentifier: bigint = NRln.genIdentifier()
const rlnIdentifier: bigint = RLN.genIdentifier()
const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment)
const witness: FullProof = NRln.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier)
const witness: FullProof = RLN.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier)
expect(typeof witness).toBe("object")
})
it.skip("Generate nrln proof and verify it", async () => {
it.skip("Generate RLN proof and verify it", async () => {
/**
* Compiled NRln circuits are needed to run this test so it's being skipped in hooks
* Compiled RLN circuits are needed to run this test so it's being skipped in hooks
*/
const identity: ZkIdentity = new ZkIdentity();
identity.genSecret(SPAM_TRESHOLD);
identity.genMultipartSecret(SPAM_TRESHOLD);
const identityCommitment: bigint = identity.genIdentityCommitment();
const identitySecret: bigint[] = identity.getSecret();
const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART_SECRET);
const identitySecret: bigint[] = identity.getMultipartSecret();
const commitments: Array<bigint> = Object.assign([], identityCommitments)
commitments.push(identityCommitment)
@@ -56,30 +56,30 @@ describe("NRln", () => {
const signal = "hey hey"
const signalHash = genSignalHash(signal)
const epoch: string = genExternalNullifier("test-epoch")
const rlnIdentifier: bigint = NRln.genIdentifier()
const rlnIdentifier: bigint = RLN.genIdentifier()
const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment)
const witness: FullProof = NRln.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier)
const witness: FullProof = RLN.genWitness(identitySecret, merkleProof, epoch, signal, rlnIdentifier)
const [y, nullifier] = NRln.calculateOutput(identitySecret, BigInt(epoch), signalHash, SPAM_TRESHOLD, rlnIdentifier)
const [y, nullifier] = RLN.calculateOutput(identitySecret, BigInt(epoch), signalHash, SPAM_TRESHOLD, rlnIdentifier)
const publicSignals = [y, merkleProof.root, nullifier, signalHash, epoch, rlnIdentifier]
const vkeyPath: string = path.join("./zkeyFiles", "nrln", "verification_key.json")
const vkeyPath: string = path.join("./zkeyFiles", "rln_3", "verification_key.json")
const vKey = JSON.parse(fs.readFileSync(vkeyPath, "utf-8"))
const wasmFilePath: string = path.join("./zkeyFiles", "nrln", "rln.wasm")
const finalZkeyPath: string = path.join("./zkeyFiles", "nrln", "rln_final.zkey")
const wasmFilePath: string = path.join("./zkeyFiles", "rln_3", "rln.wasm")
const finalZkeyPath: string = path.join("./zkeyFiles", "rln_3", "rln_final.zkey")
const fullProof: FullProof = await NRln.genProof(witness, wasmFilePath, finalZkeyPath)
const res: boolean = await NRln.verifyProof(vKey, { proof: fullProof.proof, publicSignals })
const fullProof: FullProof = await RLN.genProof(witness, wasmFilePath, finalZkeyPath)
const res: boolean = await RLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals })
expect(res).toBe(true)
}, 30000)
it("Should retrieve user secret after spaming", () => {
const identity: ZkIdentity = new ZkIdentity();
identity.genSecret(SPAM_TRESHOLD);
identity.genMultipartSecret(SPAM_TRESHOLD);
const identitySecret: bigint[] = identity.getSecret();
const identitySecret: bigint[] = identity.getMultipartSecret();
const signal1 = "hey 1"
const signalHash1 = genSignalHash(signal1)
@@ -91,14 +91,14 @@ describe("NRln", () => {
const signalHash4 = genSignalHash(signal4)
const epoch: string = genExternalNullifier("test-epoch")
const rlnIdentifier: bigint = NRln.genIdentifier()
const rlnIdentifier: bigint = RLN.genIdentifier()
const [y1] = NRln.calculateOutput(identitySecret, BigInt(epoch), signalHash1, SPAM_TRESHOLD, rlnIdentifier)
const [y2] = NRln.calculateOutput(identitySecret, BigInt(epoch), signalHash2, SPAM_TRESHOLD, rlnIdentifier)
const [y3] = NRln.calculateOutput(identitySecret, BigInt(epoch), signalHash3, SPAM_TRESHOLD, rlnIdentifier)
const [y4] = NRln.calculateOutput(identitySecret, BigInt(epoch), signalHash4, SPAM_TRESHOLD, rlnIdentifier)
const [y1] = RLN.calculateOutput(identitySecret, BigInt(epoch), signalHash1, SPAM_TRESHOLD, rlnIdentifier)
const [y2] = RLN.calculateOutput(identitySecret, BigInt(epoch), signalHash2, SPAM_TRESHOLD, rlnIdentifier)
const [y3] = RLN.calculateOutput(identitySecret, BigInt(epoch), signalHash3, SPAM_TRESHOLD, rlnIdentifier)
const [y4] = RLN.calculateOutput(identitySecret, BigInt(epoch), signalHash4, SPAM_TRESHOLD, rlnIdentifier)
const retrievedSecret: bigint = NRln.retrieveSecret([signalHash1, signalHash2, signalHash3, signalHash4], [y1, y2, y3, y4])
const retrievedSecret: bigint = RLN.retrieveSecret([signalHash1, signalHash2, signalHash3, signalHash4], [y1, y2, y3, y4])
expect(retrievedSecret).toEqual(poseidonHash(identitySecret));
})

View File

@@ -1,7 +1,7 @@
import { Rln } from "../src"
import { ZkIdentity } from "../../identity/src"
import { RLN } from "../src"
import { ZkIdentity, SecretType } from "../../identity/src"
import { MerkleProof, FullProof } from "../../types"
import { genSignalHash, genExternalNullifier, generateMerkleProof, poseidonHash } from "../src/utils"
import { genSignalHash, genExternalNullifier, generateMerkleProof } from "../src/utils"
import * as path from "path"
import * as fs from "fs"
@@ -12,38 +12,39 @@ beforeAll(() => {
for (let i = 0; i < leafIndex; i++) {
const tmpIdentity = new ZkIdentity();
const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment();
const tmpCommitment: bigint = tmpIdentity.genIdentityCommitment(SecretType.MULTIPART_SECRET);
identityCommitments.push(tmpCommitment)
}
})
describe("Rln", () => {
describe("Rln functionalities", () => {
it("Generate rln witness", () => {
describe("RLN with default spam threshold", () => {
describe("RLN functionalities", () => {
it("Generate RLN witness", () => {
const identity: ZkIdentity = new ZkIdentity();
const identityCommitment: bigint = identity.genIdentityCommitment();
const secretHash: bigint = poseidonHash(identity.getSecret());
const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART_SECRET);
const secret: bigint[] = identity.getMultipartSecret();
const commitments: Array<bigint> = Object.assign([], identityCommitments)
commitments.push(identityCommitment)
const signal = "hey hey"
const epoch: string = genExternalNullifier("test-epoch")
const rlnIdentifier: bigint = Rln.genIdentifier()
const rlnIdentifier: bigint = RLN.genIdentifier()
const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 5, commitments, identityCommitment)
const witness: FullProof = Rln.genWitness(secretHash, merkleProof, epoch, signal, rlnIdentifier)
const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment)
const witness: FullProof = RLN.genWitness(secret, merkleProof, epoch, signal, rlnIdentifier)
expect(typeof witness).toBe("object")
})
it.skip("Generate rln proof and verify it", async () => {
it.skip("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();
const secretHash: bigint = poseidonHash(identity.getSecret());
const identityCommitment: bigint = identity.genIdentityCommitment();
identity.genMultipartSecret(2);
const secret: bigint[] = identity.getMultipartSecret();
console.log("multipart secret", secret);
const identityCommitment: bigint = identity.genIdentityCommitment(SecretType.MULTIPART_SECRET);
const commitments: Array<bigint> = Object.assign([], identityCommitments)
commitments.push(identityCommitment)
@@ -51,43 +52,43 @@ describe("Rln", () => {
const signal = "hey hey"
const signalHash = genSignalHash(signal)
const epoch: string = genExternalNullifier("test-epoch")
const rlnIdentifier: bigint = Rln.genIdentifier()
const rlnIdentifier: bigint = RLN.genIdentifier()
const merkleProof: MerkleProof = generateMerkleProof(15, BigInt(0), 2, commitments, identityCommitment)
const witness: FullProof = Rln.genWitness(secretHash, merkleProof, epoch, signal, rlnIdentifier)
const witness: FullProof = RLN.genWitness(secret, merkleProof, epoch, signal, rlnIdentifier)
const [y, nullifier] = Rln.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash)
const [y, nullifier] = RLN.calculateOutput(secret, BigInt(epoch), signalHash, 2, rlnIdentifier);
const publicSignals = [y, merkleProof.root, nullifier, signalHash, epoch, rlnIdentifier]
const vkeyPath: string = path.join("./zkeyFiles", "rln", "verification_key.json")
const vkeyPath: string = path.join("./zkeyFiles", "rln_default", "verification_key.json")
const vKey = JSON.parse(fs.readFileSync(vkeyPath, "utf-8"))
const wasmFilePath: string = path.join("./zkeyFiles", "rln", "rln.wasm")
const finalZkeyPath: string = path.join("./zkeyFiles", "rln", "rln_final.zkey")
const wasmFilePath: string = path.join("./zkeyFiles", "rln_default", "rln.wasm")
const finalZkeyPath: string = path.join("./zkeyFiles", "rln_default", "rln_final.zkey")
const fullProof: FullProof = await Rln.genProof(witness, wasmFilePath, finalZkeyPath)
const res: boolean = await Rln.verifyProof(vKey, { proof: fullProof.proof, publicSignals })
const fullProof: FullProof = await RLN.genProof(witness, wasmFilePath, finalZkeyPath)
const res: boolean = await RLN.verifyProof(vKey, { proof: fullProof.proof, publicSignals })
expect(res).toBe(true)
}, 30000)
it("Should retrieve user secret after spaming", () => {
const identity: ZkIdentity = new ZkIdentity();
const secretHash: bigint = poseidonHash(identity.getSecret());
// it("Should retrieve user secret after spaming", () => {
// const identity: ZkIdentity = new ZkIdentity();
// const secret: bigint[] = identity.getMultipartSecret();
const signal1 = "hey hey"
const signalHash1 = genSignalHash(signal1)
const signal2 = "hey hey again"
const signalHash2 = genSignalHash(signal2)
// const signal1 = "hey hey"
// const signalHash1 = genSignalHash(signal1)
// const signal2 = "hey hey again"
// const signalHash2 = genSignalHash(signal2)
const epoch: string = genExternalNullifier("test-epoch")
const rlnIdentifier: bigint = Rln.genIdentifier()
// const epoch: string = genExternalNullifier("test-epoch")
// const rlnIdentifier: bigint = RLN.genIdentifier()
const [y1] = Rln.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash1)
const [y2] = Rln.calculateOutput(secretHash, BigInt(epoch), rlnIdentifier, signalHash2)
// const [y1] = RLN.calculateOutput(secret, BigInt(epoch), signalHash1, 2, rlnIdentifier )
// const [y2] = RLN.calculateOutput(secret, BigInt(epoch), signalHash2, 2, rlnIdentifier)
const retrievedSecret: bigint = Rln.retrieveSecret(signalHash1, signalHash2, y1, y2)
// const retrievedSecret: bigint = RLN.retrieveSecret([signalHash1, signalHash2], [y1, y2])
expect(retrievedSecret).toEqual(secretHash)
})
// expect(retrievedSecret).toEqual(secret)
// })
})
})

View File

@@ -1,6 +1,6 @@
{
"name": "@libsem/types",
"version": "1.0.7",
"version": "1.0.8",
"description": "Common type definitions for Semaphore modules.",
"main": "src/index.ts",
"types": "dist/index.d.ts",

View File

@@ -26,4 +26,5 @@ export declare type SerializedIdentity = {
identityNullifier: string;
identityTrapdoor: string;
secret: string[];
multipartSecret: string[];
};

View File

@@ -0,0 +1 @@
84e86da6e86f333fb01d6cd1576b7b3657dca3e6