diff --git a/.biome.jsonc b/.biome.jsonc index 33c36fb..2e2035c 100644 --- a/.biome.jsonc +++ b/.biome.jsonc @@ -17,6 +17,8 @@ "overrides": [ { "include": [ + "types/ffjavascript/index.d.ts", + "packages/poseidon/test/index.test.ts", "packages/artifacts/src/cli/spinner.ts", "packages/artifacts/src/cli/commands/generate/action.ts", ], diff --git a/jest.config.ts b/jest.config.ts index 221a311..c728a5b 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,6 +1,5 @@ import { join } from 'node:path' import type { JestConfigWithTsJest } from 'ts-jest' -// import preset from 'ts-jest/' const config: JestConfigWithTsJest = { preset: 'ts-jest', @@ -12,7 +11,7 @@ const config: JestConfigWithTsJest = { }, moduleDirectories: ['node_modules', '/node_modules', '/src'], moduleFileExtensions: ['js', 'ts'], - projects: ['packages/artifacts/test'], + projects: ['packages/artifacts/test', 'packages/poseidon/test'], } export default config diff --git a/packages/poseidon/index.test.mjs b/packages/poseidon/index.test.mjs deleted file mode 100644 index 40dd878..0000000 --- a/packages/poseidon/index.test.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import { generate } from '@zk-kit/poseidon-proof' -import { unpackGroth16Proof } from '@zk-kit/utils/proof-packing' -import { keccak256 } from 'ethers/crypto' -import { toBeHex } from 'ethers/utils' -import { getCurveFromName } from 'ffjavascript' -import assert from 'node:assert/strict' -import { readFileSync } from 'node:fs' -import { dirname, join } from 'node:path' -import { after, before, describe, test } from 'node:test' -import * as poseidons from 'poseidon-lite' -import { groth16 } from 'snarkjs' - -function hash(message) { - return (BigInt(keccak256(toBeHex(message, 32))) >> BigInt(8)).toString() -} - -const PWD = dirname(import.meta.url.replace('file://', '')) -const SCOPE = 'scope' -const INPUTS = Array.from({ length: 16 }, (_, i) => i + 1).map(i => Array.from({ length: i }, (_, j) => j + 1)) - -async function generateProof(inputs) { - const numParams = inputs.length - - return generate(inputs, SCOPE, { - wasm: join(PWD, `poseidon-${numParams}.wasm`), - zkey: join(PWD, `poseidon-${numParams}.zkey`), - }) -} - -async function verifyProof({ digest, numberOfInputs, proof, scope }) { - const verifKey = JSON.parse(readFileSync(join(PWD, `poseidon-${numberOfInputs}.json`))) - return groth16.verify(verifKey, [digest, hash(scope)], unpackGroth16Proof(proof)) -} - -describe('poseidon', () => { - const scope = 'scope' - let curve - let digest - const proofs = [] - - before(async () => { - curve = await getCurveFromName('bn128') - - for (const inputs of INPUTS) { - const proof = await generateProof(inputs) - proofs.push(proof) - } - }, 30_000) - - after(async () => { - await curve.terminate() - }) - - test('Should verify all Poseidon proofs', async (t) => { - for (const proof of proofs) { - const { numberOfInputs } = proof - await t.test(`Should verify a Poseidon proof with ${numberOfInputs} parameter(s)`, async (t) => { - const result = await verifyProof(proof) - assert.strictEqual( - result, - true, - `Proof verification failed for ${numberOfInputs} parameter${numberOfInputs > 1 ? 's' : ''}`, - ) - }) - } - }) -}) diff --git a/packages/poseidon/package.json b/packages/poseidon/package.json index 7eb46e8..56d0df3 100644 --- a/packages/poseidon/package.json +++ b/packages/poseidon/package.json @@ -17,14 +17,16 @@ "scripts": { "test": "node --test index.test.mjs" }, - "files": ["poseidon-*"], + "files": [ + "poseidon-*" + ], "devDependencies": { "@ethersproject/bignumber": "^5.7.0", + "@types/snarkjs": "^0.7.8", "@zk-kit/poseidon-proof": "1.0.0-beta.4", "@zk-kit/utils": "^1.2.0", "ethers": "^6.13.1", "ffjavascript": "^0.3.0", - "poseidon-lite": "^0.2.0", "snarkjs": "^0.7.4" } } diff --git a/packages/poseidon/test/index.test.ts b/packages/poseidon/test/index.test.ts new file mode 100644 index 0000000..b68e6a3 --- /dev/null +++ b/packages/poseidon/test/index.test.ts @@ -0,0 +1,59 @@ +import { generate, type PoseidonProof } from '@zk-kit/poseidon-proof' +import { unpackGroth16Proof } from '@zk-kit/utils' +import { keccak256 } from 'ethers/crypto' +import { toBeHex } from 'ethers/utils' +import { getCurveFromName } from 'ffjavascript' +import assert from 'node:assert/strict' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { groth16 } from 'snarkjs' + +const INPUTS = Array.from({ length: 16 }, (_, i) => i + 1).map(i => ({ + inputs: Array.from({ length: i }, (_, j) => j + 1), + numberOfInputs: i, +})) +const SCOPE = 'scope' + +const hash = (message: string) => (BigInt(keccak256(toBeHex(message, 32))) >> BigInt(8)).toString() + +async function generateProof(preimages: number[]) { + const numParams = preimages.length + + return generate(preimages, SCOPE, { + wasm: join(__dirname, '..', `poseidon-${numParams}.wasm`), + zkey: join(__dirname, '..', `poseidon-${numParams}.zkey`), + }) +} + +async function verifyProof( + { digest, numberOfInputs, proof, scope }: PoseidonProof, +) { + const verifKey = JSON.parse(readFileSync(join(__dirname, '..', `poseidon-${numberOfInputs}.json`), 'utf8')) + return groth16.verify(verifKey, [digest, hash(scope)], unpackGroth16Proof(proof)) +} + +describe('poseidon', () => { + let curve: any + + beforeAll(async () => { + curve = await getCurveFromName('bn128') + }, 30_000) + + afterAll(async () => { + await curve.terminate() + }) + + it.each(INPUTS)( + 'Should verify a poseidon proof with $numberOfInputs input(s)', + async ({ inputs, numberOfInputs }) => { + const s = `${numberOfInputs > 1 ? 's' : ''}` + const proof = await generateProof(inputs) + const result = await verifyProof(proof) + assert.strictEqual( + result, + true, + `Proof verification failed for ${numberOfInputs} parameter${s}`, + ) + }, + ) +}) diff --git a/packages/artifacts/test/cli/jest.config.ts b/packages/poseidon/test/jest.config.ts similarity index 68% rename from packages/artifacts/test/cli/jest.config.ts rename to packages/poseidon/test/jest.config.ts index fd30e90..2eafb4f 100644 --- a/packages/artifacts/test/cli/jest.config.ts +++ b/packages/poseidon/test/jest.config.ts @@ -1,12 +1,12 @@ import type { JestConfigWithTsJest } from 'ts-jest' -import _sharedJestConf from '../../../../jest.config' +import _sharedJestConf from '../../../jest.config' const { collectCoverage, projects, ...sharedJestConf } = _sharedJestConf const config: JestConfigWithTsJest = { ...sharedJestConf, - displayName: 'cli', - rootDir: '../..', + displayName: 'poseidon', + rootDir: '..', } export default config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8617bc1..aec9c9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -139,6 +139,9 @@ importers: '@ethersproject/bignumber': specifier: ^5.7.0 version: 5.7.0 + '@types/snarkjs': + specifier: ^0.7.8 + version: 0.7.8 '@zk-kit/poseidon-proof': specifier: 1.0.0-beta.4 version: 1.0.0-beta.4 @@ -151,9 +154,6 @@ importers: ffjavascript: specifier: ^0.3.0 version: 0.3.0 - poseidon-lite: - specifier: ^0.2.0 - version: 0.2.1 snarkjs: specifier: ^0.7.4 version: 0.7.4 @@ -2466,9 +2466,6 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - poseidon-lite@0.2.1: - resolution: {integrity: sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog==} - possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -5751,8 +5748,6 @@ snapshots: dependencies: find-up: 4.1.0 - poseidon-lite@0.2.1: {} - possible-typed-array-names@1.0.0: {} postcss-import@15.1.0(postcss@8.4.39): diff --git a/tsconfig.json b/tsconfig.json index dd02ea5..2eee5ce 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,8 @@ "useUnknownInCatchVariables": false, "declaration": true, "allowSyntheticDefaultImports": true, - "declarationDir": "types" + "declarationDir": "types", + "typeRoots": ["node_modules/@types", "types"] }, - "include": ["jest.config.ts"] + "include": ["jest.config.ts", "packages/artifacts/test", "packages/poseidon/test"] } diff --git a/types/ffjavascript/index.d.ts b/types/ffjavascript/index.d.ts new file mode 100644 index 0000000..8def81e --- /dev/null +++ b/types/ffjavascript/index.d.ts @@ -0,0 +1,3 @@ +declare module 'ffjavascript' { + export function getCurveFromName(name: any, singleThread?: any, plugins?: any): any +}