mirror of
https://github.com/privacy-scaling-explorations/zk-kit.git
synced 2026-04-22 03:00:15 -04:00
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:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -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));
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
// })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -26,4 +26,5 @@ export declare type SerializedIdentity = {
|
||||
identityNullifier: string;
|
||||
identityTrapdoor: string;
|
||||
secret: string[];
|
||||
multipartSecret: string[];
|
||||
};
|
||||
1
zkeyFiles.zip.REMOVED.git-id
Normal file
1
zkeyFiles.zip.REMOVED.git-id
Normal file
@@ -0,0 +1 @@
|
||||
84e86da6e86f333fb01d6cd1576b7b3657dca3e6
|
||||
Reference in New Issue
Block a user