Skip to content

Commit

Permalink
Merge pull request #124 from privacy-scaling-explorations/poseidon-pr…
Browse files Browse the repository at this point in the history
…oof/inputs

Add `NUMBER_OF_INPUTS` to `poseidon-proof`
  • Loading branch information
cedoor committed Jan 16, 2024
2 parents aec6515 + 4800453 commit 6f17255
Show file tree
Hide file tree
Showing 12 changed files with 722 additions and 158 deletions.
2 changes: 1 addition & 1 deletion packages/circuits/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
## Circuits

- Circom:
- [PoseidonProof](./circom/poseidon-proof.circom): It proves the possession of a Poseidon pre-image without revealing the pre-image itself.
- [PoseidonProof](./circom/poseidon-proof.circom): It proves the possession of Poseidon pre-images without revealing the pre-images themselves.
- [BinaryMerkleRoot](./circom/binary-merkle-root.circom): It calculates the root of a binary Merkle tree using a provided proof-of-membership.
- Noir:
- [Sparse Merkle Tree PoseidonBN254](./noir/crates/smt_bn254/src/lib.nr): A reusable library of functions related to Sparse Merkle Trees based on the JS implementation of [@zk-kit/smt](../smt). The library uses the Poseidon hash to implement the following functions:
Expand Down
4 changes: 3 additions & 1 deletion packages/circuits/circom/circuits.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"poseidon-proof": {
"file": "poseidon-proof",
"template": "PoseidonProof"
"template": "PoseidonProof",
"pubs": ["scope"],
"params": [1]
},
"binary-merkle-root": {
"file": "binary-merkle-root",
Expand Down
21 changes: 13 additions & 8 deletions packages/circuits/circom/poseidon-proof.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@ pragma circom 2.1.5;

include "poseidon.circom";

// This circuit can be used to prove the possession of a pre-image of a
// This circuit can be used to prove the possession of pre-images of a
// hash without revealing the pre-image itself. It utilizes the Poseidon
// hash function, a highly efficient and secure hash function suited
// for zero-knowledge proof contexts.
// for zero-knowledge proof contexts. A parameter is defined to specify
// the number of inputs a Poseidon hash function can support
// (i.e. 'NUMBER_OF_INPUTS').
// A scope value can be used to define a nullifier to prevent the same
// proof from being re-used twice.
template PoseidonProof() {
// The circuit takes two inputs: the pre-image and an additional scope parameter.
signal input preimage;
template PoseidonProof(NUMBER_OF_INPUTS) {
// The circuit takes two inputs: the pre-images and an additional scope parameter.
signal input preimages[NUMBER_OF_INPUTS];
signal input scope;

assert (NUMBER_OF_INPUTS >= 1);
assert (NUMBER_OF_INPUTS <= 16);

// It applies the Poseidon hash function to the pre-image to produce a hash digest.
signal output digest;
digest <== Poseidon(1)([preimage]);
digest <== Poseidon(NUMBER_OF_INPUTS)(preimages);

// A nullifier is also computed using both the pre-image and the scope, providing a value
// A nullifier is also computed using both the scope and the digest, providing a value
// to prevent the same proof from being reused twice.
signal output nullifier;
nullifier <== Poseidon(2)([scope, preimage]);
nullifier <== Poseidon(2)([scope, digest]);
}
16 changes: 9 additions & 7 deletions packages/circuits/tests/poseidon-proof.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { WitnessTester } from "circomkit"
import { poseidon1, poseidon2 } from "poseidon-lite"
import { poseidon2, poseidon3 } from "poseidon-lite"
import { circomkit } from "./common"

describe("poseidon-proof", () => {
let circuit: WitnessTester<["preimage", "scope"], ["digest", "nullifier"]>
let circuit: WitnessTester<["preimages", "scope"], ["digest", "nullifier"]>

const preimage = 3
const numberOfInputs = 3
const preimages = [1, 2, 3]
const scope = 2
const digest = poseidon1([preimage])
const nullifier = poseidon2([scope, preimage])
const digest = poseidon3(preimages)
const nullifier = poseidon2([scope, digest])

const INPUT = {
preimage,
preimages,
scope
}

Expand All @@ -23,7 +24,8 @@ describe("poseidon-proof", () => {
before(async () => {
circuit = await circomkit.WitnessTester("poseidon-proof", {
file: "poseidon-proof",
template: "PoseidonProof"
template: "PoseidonProof",
params: [numberOfInputs]
})
})

Expand Down
5 changes: 0 additions & 5 deletions packages/poseidon-proof/src/config.ts

This file was deleted.

16 changes: 8 additions & 8 deletions packages/poseidon-proof/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,34 @@ import packProof from "./pack-proof"
import { PoseidonProof, SnarkArtifacts } from "./types"

/**
* Creates a zero-knowledge proof to prove that you have the pre-image of a hash,
* without disclosing the actual preimage itself.
* Creates a zero-knowledge proof to prove that you have the preimages of a hash,
* without disclosing the actual preimages themselves.
* The use of a scope parameter along with a nullifier helps ensure the uniqueness
* and non-reusability of the proofs, enhancing security in applications like
* blockchain transactions or private data verification.
* If, for example, this package were used with Semaphore to demonstrate possession
* of a Semaphore identity of a group of voters, the scope could be the poll's ID.
* @param preimage The preimage of the hash.
* @param preimages The preimages of the hash.
* @param scope A public value used to contextualize the cryptographic proof
* and calculate the nullifier.
* @param snarkArtifacts The Snark artifacts (wasm and zkey files) generated in
* a trusted setup of the circuit are necessary to generate valid proofs
* @returns The Poseidon zero-knowledge proof.
*/
export default async function generate(
preimage: BytesLike | Hexable | number | bigint,
preimages: Array<BytesLike | Hexable | number | bigint>,
scope: BytesLike | Hexable | number | bigint,
snarkArtifacts?: SnarkArtifacts
): Promise<PoseidonProof> {
// If the Snark artifacts are not defined they will be automatically downloaded.
/* istanbul ignore next */
if (!snarkArtifacts) {
snarkArtifacts = await getSnarkArtifacts()
snarkArtifacts = await getSnarkArtifacts(preimages.length)
}

const { proof, publicSignals } = await prove(
{
in: hash(preimage),
preimages: preimages.map((preimage) => hash(preimage)),
scope: hash(scope)
},
snarkArtifacts.wasmFilePath,
Expand All @@ -43,8 +43,8 @@ export default async function generate(

return {
scope: BigNumber.from(scope).toString() as NumericString,
digest: publicSignals[1],
nullifier: publicSignals[0],
digest: publicSignals[0],
nullifier: publicSignals[1],
proof: packProof(proof)
}
}
10 changes: 7 additions & 3 deletions packages/poseidon-proof/src/get-snark-artifacts.browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
/* istanbul ignore file */
import { defaultSnarkArtifacts } from "./config"

export default async function getSnarkArtifacts() {
return defaultSnarkArtifacts
import { SnarkArtifacts } from "./types"

export default async function getSnarkArtifacts(numberOfInputs: number): Promise<SnarkArtifacts> {
return {
wasmFilePath: `https://zkkit.cedoor.dev/poseidon-proof/artifacts/${numberOfInputs}/poseidon-proof.wasm`,
zkeyFilePath: `https://zkkit.cedoor.dev/poseidon-proof/artifacts/${numberOfInputs}/poseidon-proof.zkey`
}
}
24 changes: 16 additions & 8 deletions packages/poseidon-proof/src/get-snark-artifacts.node.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
/* istanbul ignore file */
import download from "download"
import tmp from "tmp"
import fs from "fs"
import { defaultSnarkArtifacts } from "./config"
import tmp from "tmp"
import { SnarkArtifacts } from "./types"

export default async function getSnarkArtifacts() {
const tmpDir = "poseidon-proof"
const tmpPath = `${tmp.tmpdir}/${tmpDir}`
export default async function getSnarkArtifacts(numberOfInputs: number): Promise<SnarkArtifacts> {
const tmpDir = `poseidon-proof`
const tmpPath = `${tmp.tmpdir}/${tmpDir}-${numberOfInputs}`

if (!fs.existsSync(tmpPath)) {
tmp.dirSync({ name: tmpDir })
tmp.dirSync({ name: `${tmpDir}-${numberOfInputs}` })
}

await download(defaultSnarkArtifacts.wasmFilePath, tmpPath)
await download(defaultSnarkArtifacts.zkeyFilePath, tmpPath)
if (fs.readdirSync(tmpPath).length !== 2) {
await download(
`https://zkkit.cedoor.dev/poseidon-proof/artifacts/${numberOfInputs}/poseidon-proof.wasm`,
tmpPath
)
await download(
`https://zkkit.cedoor.dev/poseidon-proof/artifacts/${numberOfInputs}/poseidon-proof.zkey`,
tmpPath
)
}

return {
Expand Down
95 changes: 0 additions & 95 deletions packages/poseidon-proof/src/verification-key.json

This file was deleted.

Loading

0 comments on commit 6f17255

Please sign in to comment.