From 58e058a9946d2563c4a49be796cf77b677d5f72f Mon Sep 17 00:00:00 2001 From: sripwoud Date: Wed, 25 Sep 2024 08:58:07 +0200 Subject: [PATCH] test(poseidon): use `jest` instead of built in node test runner (#144) * test: check validity of poseidon artifacts * chore: define `test` util package * test: use local test package for poseidon test * chore: fmt * refactor * chore: remove test package * fix: update deps * chore: update tsconfig `includes` * test: update snapshot --- .biome.jsonc | 2 + jest.config.ts | 3 +- .../artifacts/test/cli/integration.test.ts | 1 + packages/poseidon/index.test.mjs | 67 ------------------- packages/poseidon/package.json | 11 +-- packages/poseidon/test/index.test.ts | 34 ++++++++++ .../test/cli => poseidon/test}/jest.config.ts | 6 +- packages/poseidon/test/utils.ts | 20 ++++++ pnpm-lock.yaml | 18 +++-- tsconfig.json | 11 ++- types/ffjavascript/index.d.ts | 3 + 11 files changed, 88 insertions(+), 88 deletions(-) delete mode 100644 packages/poseidon/index.test.mjs create mode 100644 packages/poseidon/test/index.test.ts rename packages/{artifacts/test/cli => poseidon/test}/jest.config.ts (68%) create mode 100644 packages/poseidon/test/utils.ts create mode 100644 types/ffjavascript/index.d.ts 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/artifacts/test/cli/integration.test.ts b/packages/artifacts/test/cli/integration.test.ts index b0d7bb8..46263c2 100644 --- a/packages/artifacts/test/cli/integration.test.ts +++ b/packages/artifacts/test/cli/integration.test.ts @@ -79,6 +79,7 @@ Commands: "poseidon 1.0.0 1.0.0-beta.1 + 1.0.0-beta.4 semaphore 1.0.0 4.0.0-beta.9 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..27a47dd 100644 --- a/packages/poseidon/package.json +++ b/packages/poseidon/package.json @@ -17,14 +17,17 @@ "scripts": { "test": "node --test index.test.mjs" }, - "files": ["poseidon-*"], + "files": [ + "poseidon-*" + ], "devDependencies": { "@ethersproject/bignumber": "^5.7.0", + "@types/snarkjs": "^0.7.8", + "@zk-kit/artifacts": "1.9.0", "@zk-kit/poseidon-proof": "1.0.0-beta.4", - "@zk-kit/utils": "^1.2.0", - "ethers": "^6.13.1", + "@zk-kit/utils": "^1.2.1", + "ethers": "^6.13.2", "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..8c2ba32 --- /dev/null +++ b/packages/poseidon/test/index.test.ts @@ -0,0 +1,34 @@ +import { Project } from '@zk-kit/artifacts' +import { generate } from '@zk-kit/poseidon-proof' +import { getCurveFromName } from 'ffjavascript' +import { join } from 'node:path' +import { SCOPE, verifyPoseidonProof } from './utils' + +const INPUTS = Array.from({ length: 16 }, (_, i) => i + 1).map(i => ({ + inputs: Array.from({ length: i }, (_, j) => j + 1), + numberOfInputs: i, +})) + +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 proof = await generate(inputs, SCOPE, { + wasm: join(__dirname, '..', `${Project.POSEIDON}-${numberOfInputs}.wasm`), + zkey: join(__dirname, '..', `${Project.POSEIDON}-${numberOfInputs}.zkey`), + }) + const result = await verifyPoseidonProof(proof) + expect(result).toBe(true) + }, + ) +}) 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/packages/poseidon/test/utils.ts b/packages/poseidon/test/utils.ts new file mode 100644 index 0000000..8b68f41 --- /dev/null +++ b/packages/poseidon/test/utils.ts @@ -0,0 +1,20 @@ +import { Project } from '@zk-kit/artifacts' +import type { PoseidonProof } from '@zk-kit/poseidon-proof' +import { unpackGroth16Proof } from '@zk-kit/utils' +import { keccak256, toBeHex } from 'ethers' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { groth16 } from 'snarkjs' + +export const SCOPE = 'scope' + +const hash = (message: string) => (BigInt(keccak256(toBeHex(message, 32))) >> BigInt(8)).toString() + +export const verifyPoseidonProof = ( + { digest, numberOfInputs, proof, scope }: PoseidonProof, +) => { + const verifKey = JSON.parse( + readFileSync(join(__dirname, '..', `${Project.POSEIDON}-${numberOfInputs}.json`), 'utf8'), + ) + return groth16.verify(verifKey, [digest, hash(scope)], unpackGroth16Proof(proof)) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8617bc1..470b527 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -139,21 +139,24 @@ importers: '@ethersproject/bignumber': specifier: ^5.7.0 version: 5.7.0 + '@types/snarkjs': + specifier: ^0.7.8 + version: 0.7.8 + '@zk-kit/artifacts': + specifier: 1.9.0 + version: 1.9.0 '@zk-kit/poseidon-proof': specifier: 1.0.0-beta.4 version: 1.0.0-beta.4 '@zk-kit/utils': - specifier: ^1.2.0 + specifier: ^1.2.1 version: 1.2.1 ethers: - specifier: ^6.13.1 + specifier: ^6.13.2 version: 6.13.2 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 +2469,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 +5751,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..80aba28 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,14 @@ "useUnknownInCatchVariables": false, "declaration": true, "allowSyntheticDefaultImports": true, - "declarationDir": "types" + "declarationDir": "types", + "typeRoots": [ + "node_modules/@types", + "types" + ] }, - "include": ["jest.config.ts"] + "include": [ + "jest.config.ts", + "packages/*/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 +}