Compare commits

...

4 Commits

Author SHA1 Message Date
cedoor
88c3facbb7 chore: v3.15.0
Former-commit-id: c56577f2d8
2023-10-12 15:53:02 -07:00
cedoor
2fc40bf710 refactor(proof): replace groth16 functions with groth16 pkg
Former-commit-id: dd08ba1198
2023-10-12 15:52:23 -07:00
cedoor
78dcb705c5 chore: v3.14.0
Former-commit-id: 091eb436ae
2023-10-11 19:16:55 -07:00
cedoor
3c75453e69 perf(proof): use cached curve rather than a new one
Former-commit-id: 60dc748fe7
2023-10-11 19:16:23 -07:00
27 changed files with 54 additions and 570 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/cli-template-contracts-hardhat",
"version": "3.13.0",
"version": "3.15.0",
"description": "Semaphore Hardhat template.",
"license": "Unlicense",
"files": [
@@ -36,10 +36,10 @@
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.0.0",
"@semaphore-protocol/group": "3.13.0",
"@semaphore-protocol/hardhat": "3.13.0",
"@semaphore-protocol/identity": "3.13.0",
"@semaphore-protocol/proof": "3.13.0",
"@semaphore-protocol/group": "3.15.0",
"@semaphore-protocol/hardhat": "3.15.0",
"@semaphore-protocol/identity": "3.15.0",
"@semaphore-protocol/proof": "3.15.0",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/chai": "^4.2.0",
@@ -58,7 +58,7 @@
"typescript": ">=4.5.0"
},
"dependencies": {
"@semaphore-protocol/contracts": "3.13.0"
"@semaphore-protocol/contracts": "3.15.0"
},
"config": {
"solidity": {

View File

@@ -18,10 +18,10 @@
"@nomicfoundation/hardhat-chai-matchers": "^1.0.5",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@semaphore-protocol/group": "3.13.0",
"@semaphore-protocol/hardhat": "3.13.0",
"@semaphore-protocol/identity": "3.13.0",
"@semaphore-protocol/proof": "3.13.0",
"@semaphore-protocol/group": "3.15.0",
"@semaphore-protocol/hardhat": "3.15.0",
"@semaphore-protocol/identity": "3.15.0",
"@semaphore-protocol/proof": "3.15.0",
"@typechain/ethers-v5": "^10.0.0",
"@typechain/hardhat": "^6.0.0",
"@types/chai": "^4.3.1",
@@ -40,7 +40,7 @@
"typechain": "^8.0.0"
},
"dependencies": {
"@semaphore-protocol/contracts": "3.13.0"
"@semaphore-protocol/contracts": "3.15.0"
},
"config": {
"solidity": {

View File

@@ -10,10 +10,10 @@
},
"dependencies": {
"@next/font": "13.0.3",
"@semaphore-protocol/data": "3.13.0",
"@semaphore-protocol/group": "3.13.0",
"@semaphore-protocol/identity": "3.13.0",
"@semaphore-protocol/proof": "3.13.0",
"@semaphore-protocol/data": "3.15.0",
"@semaphore-protocol/group": "3.15.0",
"@semaphore-protocol/identity": "3.15.0",
"@semaphore-protocol/proof": "3.15.0",
"@types/react": "18.0.25",
"@types/react-dom": "18.0.8",
"dotenv": "^16.0.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/cli-template-monorepo-ethers",
"version": "3.13.0",
"version": "3.15.0",
"description": "Semaphore Hardhat + Next.js + SemaphoreEthers template.",
"license": "Unlicense",
"files": [

View File

@@ -18,10 +18,10 @@
"@nomicfoundation/hardhat-chai-matchers": "^1.0.5",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@semaphore-protocol/group": "3.13.0",
"@semaphore-protocol/hardhat": "3.13.0",
"@semaphore-protocol/identity": "3.13.0",
"@semaphore-protocol/proof": "3.13.0",
"@semaphore-protocol/group": "3.15.0",
"@semaphore-protocol/hardhat": "3.15.0",
"@semaphore-protocol/identity": "3.15.0",
"@semaphore-protocol/proof": "3.15.0",
"@typechain/ethers-v5": "^10.0.0",
"@typechain/hardhat": "^6.0.0",
"@types/chai": "^4.3.1",
@@ -40,7 +40,7 @@
"typechain": "^8.0.0"
},
"dependencies": {
"@semaphore-protocol/contracts": "3.13.0"
"@semaphore-protocol/contracts": "3.15.0"
},
"config": {
"solidity": {

View File

@@ -10,10 +10,10 @@
},
"dependencies": {
"@next/font": "13.0.3",
"@semaphore-protocol/data": "3.13.0",
"@semaphore-protocol/group": "3.13.0",
"@semaphore-protocol/identity": "3.13.0",
"@semaphore-protocol/proof": "3.13.0",
"@semaphore-protocol/data": "3.15.0",
"@semaphore-protocol/group": "3.15.0",
"@semaphore-protocol/identity": "3.15.0",
"@semaphore-protocol/proof": "3.15.0",
"@types/react": "18.0.25",
"@types/react-dom": "18.0.8",
"dotenv": "^16.0.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/cli-template-monorepo-subgraph",
"version": "3.13.0",
"version": "3.15.0",
"description": "Semaphore Hardhat + Next.js + SemaphoreSubgraph template.",
"license": "Unlicense",
"files": [

View File

@@ -1,7 +1,7 @@
{
"name": "@semaphore-protocol/cli",
"type": "module",
"version": "3.13.0",
"version": "3.15.0",
"description": "A command line tool to set up your Semaphore project and get group data.",
"license": "MIT",
"bin": {
@@ -42,7 +42,7 @@
"ts-node": "^10.9.1"
},
"dependencies": {
"@semaphore-protocol/data": "3.13.0",
"@semaphore-protocol/data": "3.15.0",
"axios": "^1.3.2",
"boxen": "^7.0.1",
"chalk": "^5.1.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/contracts",
"version": "3.13.0",
"version": "3.15.0",
"description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
"license": "MIT",
"files": [

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/data",
"version": "3.13.0",
"version": "3.15.0",
"description": "A library to query Semaphore contracts.",
"license": "MIT",
"main": "dist/index.node.js",

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/group",
"version": "3.13.0",
"version": "3.15.0",
"description": "A library to create and manage Semaphore groups.",
"license": "MIT",
"main": "dist/index.node.js",

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/hardhat",
"version": "3.13.0",
"version": "3.15.0",
"description": "A Semaphore Hardhat plugin to deploy verifiers and Semaphore contract.",
"license": "MIT",
"main": "dist/index.node.js",
@@ -38,7 +38,7 @@
},
"dependencies": {
"@nomiclabs/hardhat-ethers": "^2.1.1",
"@semaphore-protocol/contracts": "3.13.0",
"@semaphore-protocol/contracts": "3.15.0",
"circomlibjs": "^0.1.7",
"ethers": "^5.7.1",
"hardhat-dependency-compiler": "^1.1.3"

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/heyauthn",
"version": "3.13.0",
"version": "3.15.0",
"description": "A library to allow developers to create and manage Semaphore identities using WebAuthn",
"license": "MIT",
"main": "dist/index.node.js",
@@ -33,7 +33,7 @@
"rollup-plugin-typescript2": "^0.31.2"
},
"dependencies": {
"@semaphore-protocol/identity": "3.13.0",
"@semaphore-protocol/identity": "3.15.0",
"@simplewebauthn/browser": "7.2.0",
"@simplewebauthn/server": "7.2.0"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@semaphore-protocol/identity",
"version": "3.13.0",
"version": "3.15.0",
"description": "A library to create Semaphore identities.",
"license": "MIT",
"main": "dist/index.node.js",

View File

@@ -1,16 +1,12 @@
{
"name": "@semaphore-protocol/proof",
"version": "3.13.0",
"version": "3.15.0",
"description": "A library to generate and verify Semaphore proofs.",
"license": "MIT",
"main": "dist/index.node.js",
"exports": {
"node": {
"import": "./dist/index.node.mjs",
"require": "./dist/index.node.js"
},
"browser": "./dist/index.browser.mjs",
"default": "./dist/index.browser.mjs"
"import": "./dist/index.node.mjs",
"require": "./dist/index.node.js"
},
"types": "dist/types/index.d.ts",
"files": [
@@ -26,21 +22,16 @@
},
"scripts": {
"build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
"build": "rimraf dist && yarn build:browser && yarn build:node",
"build:browser": "rollup -c rollup.browser.config.ts --configPlugin typescript",
"build:node": "rollup -c rollup.node.config.ts --configPlugin typescript",
"build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
"prepublishOnly": "yarn build"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@iden3/binfileutils": "0.0.11",
"@rollup/plugin-commonjs": "^24.1.0",
"@rollup/plugin-json": "^5.0.1",
"@rollup/plugin-node-resolve": "^15.0.2",
"@rollup/plugin-virtual": "^3.0.2",
"fastfile": "0.0.20",
"poseidon-lite": "^0.2.0",
"rimraf": "^5.0.5",
"rollup": "^4.0.2",
@@ -48,16 +39,15 @@
"rollup-plugin-typescript2": "^0.31.2"
},
"peerDependencies": {
"@semaphore-protocol/group": "3.13.0",
"@semaphore-protocol/identity": "3.13.0"
"@semaphore-protocol/group": "3.15.0",
"@semaphore-protocol/identity": "3.15.0"
},
"dependencies": {
"@ethersproject/bignumber": "^5.5.0",
"@ethersproject/bytes": "^5.7.0",
"@ethersproject/keccak256": "^5.7.0",
"@ethersproject/strings": "^5.5.0",
"@zk-kit/incremental-merkle-tree": "0.4.3",
"circom_runtime": "0.1.24",
"ffjavascript": "0.2.60"
"@zk-kit/groth16": "0.1.0",
"@zk-kit/incremental-merkle-tree": "0.4.3"
}
}

View File

@@ -1,58 +0,0 @@
import commonjs from "@rollup/plugin-commonjs"
import json from "@rollup/plugin-json"
import { nodeResolve } from "@rollup/plugin-node-resolve"
import virtual from "@rollup/plugin-virtual"
import * as fs from "fs"
import cleanup from "rollup-plugin-cleanup"
import typescript from "rollup-plugin-typescript2"
// Needed by fastfile.
import { O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC } from "constants"
const constants = `
export const O_TRUNC = ${O_TRUNC};
export const O_CREAT = ${O_CREAT};
export const O_RDWR = ${O_RDWR};
export const O_EXCL = ${O_EXCL};
export const O_RDONLY = ${O_RDONLY}
`
const empty = "export default {}"
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8"))
const banner = `/**
* @module ${pkg.name}
* @version ${pkg.version}
* @file ${pkg.description}
* @copyright Ethereum Foundation 2022
* @license ${pkg.license}
* @see [Github]{@link ${pkg.homepage}}
*/`
export default {
input: "src/index.ts",
output: [
{
file: pkg.exports.browser,
format: "es",
banner
}
],
external: Object.keys(pkg.dependencies),
plugins: [
typescript({
tsconfig: "./build.tsconfig.json",
useTsconfigDeclarationDir: true
}),
virtual({
fs: empty,
constants
}),
nodeResolve(),
commonjs({
esmExternals: true
}),
cleanup({ comments: "jsdoc" }),
json()
]
}

View File

@@ -19,13 +19,13 @@ export default {
input: "src/index.ts",
output: [
{
file: pkg.exports.node.require,
file: pkg.exports.require,
format: "cjs",
banner,
exports: "auto"
},
{
file: pkg.exports.node.import,
file: pkg.exports.import,
format: "es",
banner
}

View File

@@ -2,12 +2,12 @@ import { BigNumber } from "@ethersproject/bignumber"
import { BytesLike, Hexable } from "@ethersproject/bytes"
import { Group } from "@semaphore-protocol/group"
import type { Identity } from "@semaphore-protocol/identity"
import { prove } from "@zk-kit/groth16"
import { MerkleProof } from "@zk-kit/incremental-merkle-tree"
import type { NumericString } from "snarkjs"
import hash from "./hash"
import packProof from "./packProof"
import { SemaphoreProof, SnarkArtifacts } from "./types"
import groth16Prove from "./groth16/prove"
/**
* Generates a Semaphore proof.
@@ -46,7 +46,7 @@ export default async function generateProof(
}
}
const { proof, publicSignals } = await groth16Prove(
const { proof, publicSignals } = await prove(
{
identityTrapdoor: trapdoor,
identityNullifier: nullifier,

View File

@@ -1,226 +0,0 @@
/* eslint-disable no-plusplus */
/* eslint-disable eqeqeq */
/* eslint-disable @typescript-eslint/naming-convention */
/* istanbul ignore file */
// @ts-ignore
import * as binFileUtils from "@iden3/binfileutils"
import { BigBuffer, Scalar, utils } from "ffjavascript"
import { log2 } from "./utils"
import * as zkeyUtils from "./zkey-utils"
import * as wtnsUtils from "./wtns-utils"
import wtnsCalculate from "./wtns-calculate"
const { stringifyBigInts, unstringifyBigInts } = utils
async function buildABC1(curve: any, zkey: any, witness: any, coeffs: any) {
const { n8 } = curve.Fr
const sCoef = 4 * 3 + zkey.n8r
const nCoef = (coeffs.byteLength - 4) / sCoef
const outBuffA = new BigBuffer(zkey.domainSize * n8)
const outBuffB = new BigBuffer(zkey.domainSize * n8)
const outBuffC = new BigBuffer(zkey.domainSize * n8)
const outBuf = [outBuffA, outBuffB]
for (let i = 0; i < nCoef; i++) {
const buffCoef = coeffs.slice(4 + i * sCoef, 4 + i * sCoef + sCoef)
const buffCoefV = new DataView(buffCoef.buffer)
const m = buffCoefV.getUint32(0, true)
const c = buffCoefV.getUint32(4, true)
const s = buffCoefV.getUint32(8, true)
const coef = buffCoef.slice(12, 12 + n8)
outBuf[m].set(
curve.Fr.add(outBuf[m].slice(c * n8, c * n8 + n8), curve.Fr.mul(coef, witness.slice(s * n8, s * n8 + n8))),
c * n8
)
}
for (let i = 0; i < zkey.domainSize; i++) {
outBuffC.set(curve.Fr.mul(outBuffA.slice(i * n8, i * n8 + n8), outBuffB.slice(i * n8, i * n8 + n8)), i * n8)
}
return [outBuffA, outBuffB, outBuffC]
}
async function joinABC(curve: any, _zkey: any, a: any, b: any, c: any) {
const MAX_CHUNK_SIZE = 1 << 22
const { n8 } = curve.Fr
const nElements = Math.floor(a.byteLength / curve.Fr.n8)
const promises = []
for (let i = 0; i < nElements; i += MAX_CHUNK_SIZE) {
const n = Math.min(nElements - i, MAX_CHUNK_SIZE)
const task = []
const aChunk = a.slice(i * n8, (i + n) * n8)
const bChunk = b.slice(i * n8, (i + n) * n8)
const cChunk = c.slice(i * n8, (i + n) * n8)
task.push({ cmd: "ALLOCSET", var: 0, buff: aChunk })
task.push({ cmd: "ALLOCSET", var: 1, buff: bChunk })
task.push({ cmd: "ALLOCSET", var: 2, buff: cChunk })
task.push({ cmd: "ALLOC", var: 3, len: n * n8 })
task.push({
cmd: "CALL",
fnName: "qap_joinABC",
params: [{ var: 0 }, { var: 1 }, { var: 2 }, { val: n }, { var: 3 }]
})
task.push({ cmd: "CALL", fnName: "frm_batchFromMontgomery", params: [{ var: 3 }, { val: n }, { var: 3 }] })
task.push({ cmd: "GET", out: 0, var: 3, len: n * n8 })
promises.push(curve.tm.queueAction(task))
}
const result = await Promise.all(promises)
let outBuff
if (a instanceof BigBuffer) {
// @ts-ignore
outBuff = new BigBuffer(a.byteLength)
} else {
outBuff = new Uint8Array(a.byteLength)
}
let p = 0
for (let i = 0; i < result.length; i++) {
outBuff.set(result[i][0], p)
p += result[i][0].byteLength
}
return outBuff
}
export default async function groth16Prove(_input: any, wasmFile: any, zkeyFileName: any) {
const input = unstringifyBigInts(_input)
const witnessFileName = {
type: "mem"
}
await wtnsCalculate(input, wasmFile, witnessFileName)
const { fd: fdWtns, sections: sectionsWtns } = await binFileUtils.readBinFile(
witnessFileName,
"wtns",
2,
1 << 25,
1 << 23
)
const wtns = await wtnsUtils.readHeader(fdWtns, sectionsWtns)
const { fd: fdZKey, sections: sectionsZKey } = await binFileUtils.readBinFile(
zkeyFileName,
"zkey",
2,
1 << 25,
1 << 23
)
const zkey = await zkeyUtils.readHeader(fdZKey, sectionsZKey, undefined)
if (zkey.protocol !== "groth16") {
throw new Error("zkey file is not groth16")
}
if (!Scalar.eq(zkey.r, wtns.q)) {
throw new Error("Curve of the witness does not match the curve of the proving key")
}
if (wtns.nWitness !== zkey.nVars) {
throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}`)
}
const { curve } = zkey
const { Fr } = curve
const { G1 } = curve
const { G2 } = curve
const power = log2(zkey.domainSize)
const buffWitness = await binFileUtils.readSection(fdWtns, sectionsWtns, 2)
const buffCoeffs = await binFileUtils.readSection(fdZKey, sectionsZKey, 4)
const [buffA_T, buffB_T, buffC_T] = await buildABC1(curve, zkey, buffWitness, buffCoeffs)
const inc = power == Fr.s ? curve.Fr.shift : curve.Fr.w[power + 1]
const buffA = await Fr.ifft(buffA_T, "", "", undefined, "IFFT_A")
const buffAodd = await Fr.batchApplyKey(buffA, Fr.e(1), inc)
const buffAodd_T = await Fr.fft(buffAodd, "", "", undefined, "FFT_A")
const buffB = await Fr.ifft(buffB_T, "", "", undefined, "IFFT_B")
const buffBodd = await Fr.batchApplyKey(buffB, Fr.e(1), inc)
const buffBodd_T = await Fr.fft(buffBodd, "", "", undefined, "FFT_B")
const buffC = await Fr.ifft(buffC_T, "", "", undefined, "IFFT_C")
const buffCodd = await Fr.batchApplyKey(buffC, Fr.e(1), inc)
const buffCodd_T = await Fr.fft(buffCodd, "", "", undefined, "FFT_C")
const buffPodd_T = await joinABC(curve, zkey, buffAodd_T, buffBodd_T, buffCodd_T)
let proof: any = {}
const buffBasesA = await binFileUtils.readSection(fdZKey, sectionsZKey, 5)
proof.pi_a = await curve.G1.multiExpAffine(buffBasesA, buffWitness, undefined, "multiexp A")
const buffBasesB1 = await binFileUtils.readSection(fdZKey, sectionsZKey, 6)
let pib1 = await curve.G1.multiExpAffine(buffBasesB1, buffWitness, undefined, "multiexp B1")
const buffBasesB2 = await binFileUtils.readSection(fdZKey, sectionsZKey, 7)
proof.pi_b = await curve.G2.multiExpAffine(buffBasesB2, buffWitness, undefined, "multiexp B2")
const buffBasesC = await binFileUtils.readSection(fdZKey, sectionsZKey, 8)
proof.pi_c = await curve.G1.multiExpAffine(
buffBasesC,
buffWitness.slice((zkey.nPublic + 1) * curve.Fr.n8),
undefined,
"multiexp C"
)
const buffBasesH = await binFileUtils.readSection(fdZKey, sectionsZKey, 9)
const resH = await curve.G1.multiExpAffine(buffBasesH, buffPodd_T, undefined, "multiexp H")
const r = curve.Fr.random()
const s = curve.Fr.random()
proof.pi_a = G1.add(proof.pi_a, zkey.vk_alpha_1)
proof.pi_a = G1.add(proof.pi_a, G1.timesFr(zkey.vk_delta_1, r))
proof.pi_b = G2.add(proof.pi_b, zkey.vk_beta_2)
proof.pi_b = G2.add(proof.pi_b, G2.timesFr(zkey.vk_delta_2, s))
pib1 = G1.add(pib1, zkey.vk_beta_1)
pib1 = G1.add(pib1, G1.timesFr(zkey.vk_delta_1, s))
proof.pi_c = G1.add(proof.pi_c, resH)
proof.pi_c = G1.add(proof.pi_c, G1.timesFr(proof.pi_a, s))
proof.pi_c = G1.add(proof.pi_c, G1.timesFr(pib1, r))
proof.pi_c = G1.add(proof.pi_c, G1.timesFr(zkey.vk_delta_1, Fr.neg(Fr.mul(r, s))))
let publicSignals = []
for (let i = 1; i <= zkey.nPublic; i++) {
const b = buffWitness.slice(i * Fr.n8, i * Fr.n8 + Fr.n8)
publicSignals.push(Scalar.fromRprLE(b, undefined, undefined))
}
proof.pi_a = G1.toObject(G1.toAffine(proof.pi_a))
proof.pi_b = G2.toObject(G2.toAffine(proof.pi_b))
proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c))
proof.protocol = "groth16"
proof.curve = curve.name
await fdZKey.close()
await fdWtns.close()
proof = stringifyBigInts(proof)
publicSignals = stringifyBigInts(publicSignals)
return { proof, publicSignals }
}

View File

@@ -1,14 +0,0 @@
/* eslint-disable import/prefer-default-export */
/* eslint-disable no-return-assign */
/* istanbul ignore file */
export function log2(V: any) {
return (
((V & 0xffff0000) !== 0 ? ((V &= 0xffff0000), 16) : 0) |
((V & 0xff00ff00) !== 0 ? ((V &= 0xff00ff00), 8) : 0) |
((V & 0xf0f0f0f0) !== 0 ? ((V &= 0xf0f0f0f0), 4) : 0) |
((V & 0xcccccccc) !== 0 ? ((V &= 0xcccccccc), 2) : 0) |
// @ts-ignore
((V & 0xaaaaaaaa) !== 0)
)
}

View File

@@ -1,73 +0,0 @@
/* eslint-disable no-plusplus */
/* eslint-disable @typescript-eslint/naming-convention */
/* istanbul ignore file */
import { Scalar, utils, buildBn128 } from "ffjavascript"
const { unstringifyBigInts } = utils
function isWellConstructed(curve: any, proof: any) {
const { G1 } = curve
const { G2 } = curve
return G1.isValid(proof.pi_a) && G2.isValid(proof.pi_b) && G1.isValid(proof.pi_c)
}
function publicInputsAreValid(curve: any, publicInputs: any) {
for (let i = 0; i < publicInputs.length; i++) {
if (!Scalar.lt(publicInputs[i], curve.r)) {
return false
}
}
return true
}
export default async function groth16Verify(_vk_verifier: any, _publicSignals: any, _proof: any) {
const vk_verifier = unstringifyBigInts(_vk_verifier)
const proof = unstringifyBigInts(_proof)
const publicSignals = unstringifyBigInts(_publicSignals)
const curve = await buildBn128(undefined, undefined)
const IC0 = curve.G1.fromObject(vk_verifier.IC[0])
const IC = new Uint8Array(curve.G1.F.n8 * 2 * publicSignals.length)
const w = new Uint8Array(curve.Fr.n8 * publicSignals.length)
if (!publicInputsAreValid(curve, publicSignals)) {
return false
}
for (let i = 0; i < publicSignals.length; i++) {
const buffP = curve.G1.fromObject(vk_verifier.IC[i + 1])
IC.set(buffP, i * curve.G1.F.n8 * 2)
Scalar.toRprLE(w, curve.Fr.n8 * i, publicSignals[i], curve.Fr.n8)
}
let cpub = await curve.G1.multiExpAffine(IC, w)
cpub = curve.G1.add(cpub, IC0)
const pi_a = curve.G1.fromObject(proof.pi_a)
const pi_b = curve.G2.fromObject(proof.pi_b)
const pi_c = curve.G1.fromObject(proof.pi_c)
if (!isWellConstructed(curve, { pi_a, pi_b, pi_c })) {
return false
}
const vk_gamma_2 = curve.G2.fromObject(vk_verifier.vk_gamma_2)
const vk_delta_2 = curve.G2.fromObject(vk_verifier.vk_delta_2)
const vk_alpha_1 = curve.G1.fromObject(vk_verifier.vk_alpha_1)
const vk_beta_2 = curve.G2.fromObject(vk_verifier.vk_beta_2)
return curve.pairingEq(
curve.G1.neg(pi_a),
pi_b,
cpub,
vk_gamma_2,
pi_c,
vk_delta_2,
vk_alpha_1,
vk_beta_2
)
}

View File

@@ -1,39 +0,0 @@
/* eslint-disable eqeqeq */
/* istanbul ignore file */
// @ts-ignore
import * as binFileUtils from "@iden3/binfileutils"
// @ts-ignore
import { WitnessCalculatorBuilder } from "circom_runtime"
// @ts-ignore
import * as fastFile from "fastfile"
import { utils } from "ffjavascript"
import * as wtnsUtils from "./wtns-utils"
const { unstringifyBigInts } = utils
export default async function wtnsCalculate(_input: any, wasmFileName: any, wtnsFileName: any) {
const input = unstringifyBigInts(_input)
const fdWasm = await fastFile.readExisting(wasmFileName)
const wasm = await fdWasm.read(fdWasm.totalSize)
await fdWasm.close()
const wc = await WitnessCalculatorBuilder(wasm)
if (wc.circom_version() == 1) {
const w = await wc.calculateBinWitness(input)
const fdWtns = await binFileUtils.createBinFile(wtnsFileName, "wtns", 2, 2)
await wtnsUtils.writeBin(fdWtns, w, wc.prime)
await fdWtns.close()
} else {
const fdWtns = await fastFile.createOverride(wtnsFileName)
const w = await wc.calculateWTNSBin(input)
await fdWtns.write(w)
await fdWtns.close()
}
}

View File

@@ -1,32 +0,0 @@
/* eslint-disable eqeqeq */
/* istanbul ignore file */
// @ts-ignore
import * as binFileUtils from "@iden3/binfileutils"
import { Scalar } from "ffjavascript"
export async function writeBin(fd: any, witnessBin: any, prime: any) {
await binFileUtils.startWriteSection(fd, 1)
const n8 = (Math.floor((Scalar.bitLength(prime) - 1) / 64) + 1) * 8
await fd.writeULE32(n8)
await binFileUtils.writeBigInt(fd, prime, n8)
if (witnessBin.byteLength % n8 != 0) {
throw new Error("Invalid witness length")
}
await fd.writeULE32(witnessBin.byteLength / n8)
await binFileUtils.endWriteSection(fd)
await binFileUtils.startWriteSection(fd, 2)
await fd.write(witnessBin)
await binFileUtils.endWriteSection(fd)
}
export async function readHeader(fd: any, sections: any) {
await binFileUtils.startReadUniqueSection(fd, sections, 1)
const n8 = await fd.readULE32()
const q = await binFileUtils.readBigInt(fd, n8)
const nWitness = await fd.readULE32()
await binFileUtils.endReadSection(fd)
return { n8, q, nWitness }
}

View File

@@ -1,60 +0,0 @@
/* eslint-disable import/prefer-default-export */
/* istanbul ignore file */
// @ts-ignore
import * as binFileUtils from "@iden3/binfileutils"
import { buildBn128 } from "ffjavascript"
import { log2 } from "./utils"
async function readG1(fd: any, curve: any, toObject: any) {
const buff = await fd.read(curve.G1.F.n8 * 2)
const res = curve.G1.fromRprLEM(buff, 0)
return toObject ? curve.G1.toObject(res) : res
}
async function readG2(fd: any, curve: any, toObject: any) {
const buff = await fd.read(curve.G2.F.n8 * 2)
const res = curve.G2.fromRprLEM(buff, 0)
return toObject ? curve.G2.toObject(res) : res
}
async function readHeaderGroth16(fd: any, sections: any, toObject: any) {
const zkey: any = {}
zkey.protocol = "groth16"
await binFileUtils.startReadUniqueSection(fd, sections, 2)
const n8q = await fd.readULE32()
zkey.n8q = n8q
zkey.q = await binFileUtils.readBigInt(fd, n8q)
const n8r = await fd.readULE32()
zkey.n8r = n8r
zkey.r = await binFileUtils.readBigInt(fd, n8r)
zkey.curve = await buildBn128(undefined, undefined)
zkey.nVars = await fd.readULE32()
zkey.nPublic = await fd.readULE32()
zkey.domainSize = await fd.readULE32()
zkey.power = log2(zkey.domainSize)
zkey.vk_alpha_1 = await readG1(fd, zkey.curve, toObject)
zkey.vk_beta_1 = await readG1(fd, zkey.curve, toObject)
zkey.vk_beta_2 = await readG2(fd, zkey.curve, toObject)
zkey.vk_gamma_2 = await readG2(fd, zkey.curve, toObject)
zkey.vk_delta_1 = await readG1(fd, zkey.curve, toObject)
zkey.vk_delta_2 = await readG2(fd, zkey.curve, toObject)
await binFileUtils.endReadSection(fd)
return zkey
}
export async function readHeader(fd: any, sections: any, toObject: any) {
await binFileUtils.startReadUniqueSection(fd, sections, 1)
const protocolId = await fd.readULE32()
await binFileUtils.endReadSection(fd)
if (protocolId === 1) {
return readHeaderGroth16(fd, sections, toObject)
}
throw new Error("Protocol not supported: ")
}

View File

@@ -1,8 +1,8 @@
import { verify } from "@zk-kit/groth16"
import hash from "./hash"
import { SemaphoreProof } from "./types"
import unpackProof from "./unpackProof"
import verificationKeys from "./verificationKeys.json"
import groth16Verify from "./groth16/verify"
/**
* Verifies a Semaphore proof.
@@ -24,9 +24,8 @@ export default function verifyProof(
IC: verificationKeys.IC[treeDepth - 16]
}
return groth16Verify(
verificationKey,
[merkleTreeRoot, nullifierHash, hash(signal), hash(externalNullifier)],
unpackProof(proof)
)
return verify(verificationKey, {
publicSignals: [merkleTreeRoot, nullifierHash, hash(signal), hash(externalNullifier)],
proof: unpackProof(proof)
})
}

View File

@@ -1,7 +1,4 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"allowJs": true
},
"include": ["src", "rollup.config.ts"]
}

View File

@@ -1 +1 @@
dc2f95a0a229d9a66a7b3900e3f2c2eeb3c4cd81
56f1eae9f45dc17131882a1e18bd4d2997714e07