Merge branch 'plonk'

This commit is contained in:
Jordi Baylina 2021-05-31 13:21:37 +02:00
commit b4f063b928
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
81 changed files with 19880 additions and 676 deletions

106
.vscode/launch.json vendored Normal file

@ -0,0 +1,106 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "plonk setup",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"pks",
"test/plonk_circuit/circuit.r1cs",
"test/plonk_circuit/powersOfTau15_final.ptau",
"test/plonk_circuit/circuit.zkey"
]
},
{
"type": "pwa-node",
"request": "launch",
"name": "plonk prove",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"pkp",
"test/plonk_circuit/circuit.zkey",
"test/plonk_circuit/witness.wtns",
"test/plonk_circuit/proof.json",
"test/plonk_circuit/public.json",
"-v"
]
},
{
"type": "pwa-node",
"request": "launch",
"name": "plonk export vk",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"zkev",
"test/plonk_circuit/circuit.zkey",
"test/plonk_circuit/verification_key.json",
]
},
{
"type": "pwa-node",
"request": "launch",
"name": "plonk verify",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"pkv",
"test/plonk_circuit/verification_key.json",
"test/plonk_circuit/public.json",
"test/plonk_circuit/proof.json",
"-v"
]
},
{
"type": "pwa-node",
"request": "launch",
"name": "export solidity calldata",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"zkesc",
"test/plonk_circuit/public.json",
"test/plonk_circuit/proof.json",
]
},
{
"type": "pwa-node",
"request": "launch",
"name": "export solidity verifier",
"skipFiles": [
"<node_internals>/**"
],
"program": "cli.js",
"args": [
"zkesv",
"test/plonk_circuit/circuit.zkey",
"test/plonk_circuit/verifier.sol",
]
},
{
"type": "node",
"request": "launch",
"name": "Mocha all tests",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"cwd": "${workspaceRoot}",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

@ -299,11 +299,29 @@ cat circuit.r1cs.json
We export `r1cs` to `json` format to make it human readable.
### 14. Generate the reference `zkey` without phase 2 contributions
### 14. Setup
Currently, snarkjs supports 2 proving systems: groth16 and plonk.
Groth16 requires a trusted ceremony for each circuit. Plonk does not require it, it's enought with the powers of tau ceremony which is universal.
#### Plonk
```sh
snarkjs zkey new circuit.r1cs pot12_final.ptau circuit_0000.zkey
snarkjs plonk setup circuit.r1cs pot12_final.ptau circuit_0000.zkey
```
You can jump directly to Section 21 as plonk does not require a specific trusted ceremony.
### Groth16
```sh
snarkjs groth16 setup circuit.r1cs pot12_final.ptau circuit_0000.zkey
```
This generates the reference `zkey` without phase 2 contributions
IMPORTANT: Do not use this zkey in production, as it's not safe. It requires at least a contribution,
The `zkey new` command creates an initial `zkey` file with zero contributions.
The `zkey` is a zero-knowledge key that includes both the proving and verification keys as well as phase 2 contributions.
@ -403,11 +421,20 @@ The `wtns debug` command logs every time a new component starts/ends (`--trigger
### 24. Create the proof
#### Plonk
```sh
snarkjs plonk prove circuit_final.zkey witness.wtns proof.json public.json
```
#### Groth16
```sh
snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json
```
We create the proof. `groth16 prove` generates the files `proof.json` and `public.json`: `proof.json` contains the actual proof, whereas `public.json` contains the values of the public inputs and output.
We create the proof. this command generates the files `proof.json` and `public.json`: `proof.json` contains the actual proof, whereas `public.json` contains the values of the public inputs and output.
> Note that it's also possible to create the proof and calculate the witness in the same command by running:
> ```sh
@ -416,11 +443,18 @@ We create the proof. `groth16 prove` generates the files `proof.json` and `publi
### 25. Verify the proof
#### Plonk
```sh
snarkjs plonk verify verification_key.json public.json proof.json
```
#### Groth16
```sh
snarkjs groth16 verify verification_key.json public.json proof.json
```
We use the `groth16 verify` command to verify the proof, passing in the `verification_key` we exported earlier.
We use the this command to verify the proof, passing in the `verification_key` we exported earlier.
If all is well, you should see that `OK` has been outputted to your console. This signifies the proof is valid.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

11
build/snarkjs.min.js vendored

File diff suppressed because one or more lines are too long

199
cli.js

@ -1,20 +1,20 @@
/*
Copyright 2018 0KIMS association.
This file is part of jaz (Zero Knowledge Circuit Compiler).
This file is part of snarkJS.
jaz is a free software: you can redistribute it and/or modify it
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jaz is distributed in the hope that it will be useful, but WITHOUT
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with jaz. If not, see <https://www.gnu.org/licenses/>.
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
/* eslint-disable no-console */
@ -35,6 +35,7 @@ const {stringifyBigInts, unstringifyBigInts} = utils;
import * as zkey from "./src/zkey.js";
import * as groth16 from "./src/groth16.js";
import * as plonk from "./src/plonk.js";
import * as wtns from "./src/wtns.js";
import * as curves from "./src/curves.js";
import path from "path";
@ -166,13 +167,6 @@ const commands = [
alias: ["wej"],
action: wtnsExportJson
},
{
cmd: "zkey new [circuit.r1cs] [powersoftau.ptau] [circuit_0000.zkey]",
description: "Creates an initial pkey file with zero contributions ",
alias: ["zkn"],
options: "-verbose|v",
action: zkeyNew
},
{
cmd: "zkey contribute <circuit_old.zkey> <circuit_new.zkey>",
description: "creates a zkey file with a new contribution",
@ -242,11 +236,18 @@ const commands = [
action: zkeyExportSolidityVerifier
},
{
cmd: "zkey export soliditycalldata <public.json> <proof.json>",
cmd: "zkey export soliditycalldata [public.json] [proof.json]",
description: "Generates call parameters ready to be called.",
alias: ["zkesc", "generatecall -pub|public -p|proof"],
action: zkeyExportSolidityCalldata
},
{
cmd: "groth16 setup [circuit.r1cs] [powersoftau.ptau] [circuit_0000.zkey]",
description: "Creates an initial groth16 pkey file with zero contributions",
alias: ["g16s", "zkn", "zkey new"],
options: "-verbose|v",
action: zkeyNew
},
{
cmd: "groth16 prove [circuit_final.zkey] [witness.wtns] [proof.json] [public.json]",
description: "Generates a zk Proof from witness",
@ -267,7 +268,34 @@ const commands = [
alias: ["g16v", "verify -vk|verificationkey -pub|public -p|proof"],
action: groth16Verify
},
{
cmd: "plonk setup [circuit.r1cs] [powersoftau.ptau] [circuit.zkey]",
description: "Creates an initial PLONK pkey ",
alias: ["pks"],
options: "-verbose|v",
action: plonkSetup
},
{
cmd: "plonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json]",
description: "Generates a PLONK Proof from witness",
alias: ["pkp"],
options: "-verbose|v -protocol",
action: plonkProve
},
{
cmd: "plonk fullprove [input.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json]",
description: "Generates a PLONK Proof from input",
alias: ["pkf"],
options: "-verbose|v -protocol",
action: plonkFullProve
},
{
cmd: "plonk verify [verification_key.json] [public.json] [proof.json]",
description: "Verify a PLONK Proof",
alias: ["pkv"],
options: "-verbose|v",
action: plonkVerify
}
];
@ -303,13 +331,6 @@ TODO COMMANDS
*/
function p256(n) {
let nstr = n.toString(16);
while (nstr.length < 64) nstr = "0"+nstr;
nstr = `"0x${nstr}"`;
return nstr;
}
function changeExt(fileName, newExt) {
let S = fileName;
while ((S.length>0) && (S[S.length-1] != ".")) S = S.slice(0, S.length-1);
@ -544,15 +565,12 @@ async function zkeyExportSolidityVerifier(params, options) {
if (options.verbose) Logger.setLogLevel("DEBUG");
let templateName;
try {
templateName = path.join( __dirname, "templates", "verifier_groth16.sol");
await fs.promises.stat(templateName);
} catch (err) {
templateName = path.join( __dirname, "..", "templates", "verifier_groth16.sol");
}
const templates = {};
const verifierCode = await zkey.exportSolidityVerifier(zkeyName, templateName, logger);
templates.groth16 = await fs.promises.readFile(path.join(__dirname, "templates", "verifier_groth16.sol.ejs"), "utf8");
templates.plonk = await fs.promises.readFile(path.join(__dirname, "templates", "verifier_plonk.sol.ejs"), "utf8");
const verifierCode = await zkey.exportSolidityVerifier(zkeyName, templates, logger);
fs.writeFileSync(verifierName, verifierCode, "utf-8");
@ -582,33 +600,15 @@ async function zkeyExportSolidityCalldata(params, options) {
const pub = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
let inputs = "";
for (let i=0; i<pub.length; i++) {
if (inputs != "") inputs = inputs + ",";
inputs = inputs + p256(pub[i]);
}
let S;
if ((typeof proof.protocol === "undefined") || (proof.protocol == "original")) {
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[${p256(proof.pi_ap[0])}, ${p256(proof.pi_ap[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_bp[0])}, ${p256(proof.pi_bp[1])}],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${p256(proof.pi_cp[0])}, ${p256(proof.pi_cp[1])}],` +
`[${p256(proof.pi_h[0])}, ${p256(proof.pi_h[1])}],` +
`[${p256(proof.pi_kp[0])}, ${p256(proof.pi_kp[1])}],` +
`[${inputs}]`;
} else if ((proof.protocol == "groth16")||(proof.protocol == "kimleeoh")) {
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${inputs}]`;
let res;
if (proof.protocol == "groth16") {
res = await groth16.exportSolidityCallData(proof, pub);
} else if (proof.protocol == "plonk") {
res = await plonk.exportSolidityCallData(proof, pub);
} else {
throw new Error("InvalidProof");
throw new Error("Invalid Protocol");
}
console.log(S);
console.log(res);
return 0;
}
@ -986,3 +986,96 @@ async function zkeyBellmanContribute(params, options) {
return zkey.bellmanContribute(curve, challengeName, responseName, options.entropy, logger);
}
// plonk setup <circuit.r1cs> <powersoftau.ptau> <circuit.zkey>
async function plonkSetup(params, options) {
let r1csName;
let ptauName;
let zkeyName;
if (params.length < 1) {
r1csName = "circuit.r1cs";
} else {
r1csName = params[0];
}
if (params.length < 2) {
ptauName = "powersoftau.ptau";
} else {
ptauName = params[1];
}
if (params.length < 3) {
zkeyName = "circuit.zkey";
} else {
zkeyName = params[2];
}
if (options.verbose) Logger.setLogLevel("DEBUG");
return plonk.setup(r1csName, ptauName, zkeyName, logger);
}
// plonk prove [circuit.zkey] [witness.wtns] [proof.json] [public.json]
async function plonkProve(params, options) {
const zkeyName = params[0] || "circuit.zkey";
const witnessName = params[1] || "witness.wtns";
const proofName = params[2] || "proof.json";
const publicName = params[3] || "public.json";
if (options.verbose) Logger.setLogLevel("DEBUG");
const {proof, publicSignals} = await plonk.prove(zkeyName, witnessName, logger);
await fs.promises.writeFile(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
await fs.promises.writeFile(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
return 0;
}
// plonk fullprove [input.json] [circuit.wasm] [circuit.zkey] [proof.json] [public.json]
async function plonkFullProve(params, options) {
const inputName = params[0] || "input.json";
const wasmName = params[1] || "circuit.wasm";
const zkeyName = params[2] || "circuit.zkey";
const proofName = params[3] || "proof.json";
const publicName = params[4] || "public.json";
if (options.verbose) Logger.setLogLevel("DEBUG");
const input = unstringifyBigInts(JSON.parse(await fs.promises.readFile(inputName, "utf8")));
const {proof, publicSignals} = await plonk.fullProve(input, wasmName, zkeyName, logger);
await fs.promises.writeFile(proofName, JSON.stringify(stringifyBigInts(proof), null, 1), "utf-8");
await fs.promises.writeFile(publicName, JSON.stringify(stringifyBigInts(publicSignals), null, 1), "utf-8");
return 0;
}
// plonk verify [verification_key.json] [public.json] [proof.json]
async function plonkVerify(params, options) {
const verificationKeyName = params[0] || "verification_key.json";
const publicName = params[1] || "public.json";
const proofName = params[2] || "proof.json";
const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync(verificationKeyName, "utf8")));
const pub = unstringifyBigInts(JSON.parse(fs.readFileSync(publicName, "utf8")));
const proof = unstringifyBigInts(JSON.parse(fs.readFileSync(proofName, "utf8")));
if (options.verbose) Logger.setLogLevel("DEBUG");
const isValid = await plonk.verify(verificationKey, pub, proof, logger);
if (isValid) {
return 0;
} else {
return 1;
}
}

@ -24,6 +24,7 @@ export default {
os: empty,
crypto: empty,
readline: empty,
ejs: empty,
// Stub out a "global" module that we can inject later
global: empty,
}),

@ -5,3 +5,4 @@ export * as powersOfTau from "./src/powersoftau.js";
export * as r1cs from "./src/r1cs.js";
export * as wtns from "./src/wtns.js";
export * as zKey from "./src/zkey.js";
export * as plonk from "./src/plonk.js";

351
package-lock.json generated

@ -11,8 +11,10 @@
"@iden3/binfileutils": "0.0.8",
"blake2b-wasm": "https://github.com/jbaylina/blake2b-wasm.git",
"circom_runtime": "0.1.13",
"ejs": "^3.1.6",
"fastfile": "0.0.19",
"ffjavascript": "0.2.35",
"ffjavascript": "0.2.36",
"js-sha3": "^0.8.0",
"logplease": "^1.2.15",
"r1csfile": "0.0.32",
"readline": "^1.3.0"
@ -102,15 +104,6 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/@babel/highlight/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@babel/highlight/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -379,11 +372,15 @@
"node": ">=4"
}
},
"node_modules/async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
},
"node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"node_modules/big-integer": {
"version": "1.6.48",
@ -417,7 +414,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -541,6 +537,16 @@
"calcwit": "calcwit.js"
}
},
"node_modules/circom_runtime/node_modules/ffjavascript": {
"version": "0.2.35",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.35.tgz",
"integrity": "sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==",
"dependencies": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.14",
"web-worker": "^1.0.0"
}
},
"node_modules/cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@ -641,8 +647,7 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"node_modules/cross-spawn": {
"version": "6.0.5",
@ -753,6 +758,20 @@
"node": ">=6.0.0"
}
},
"node_modules/ejs": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
"dependencies": {
"jake": "^10.6.1"
},
"bin": {
"ejs": "bin/cli.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@ -822,6 +841,14 @@
"node": ">=6"
}
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/eslint": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
@ -957,15 +984,6 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/eslint/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/eslint/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -1130,9 +1148,9 @@
"integrity": "sha512-tz9nWR5KYb6eR2odFQ7oxqEkx8F3YQZ6NBJoJR92YEG3DqYOqyxMck8PKvTVNKx3uwvOqGnLXNScnqpdHRdHGQ=="
},
"node_modules/ffjavascript": {
"version": "0.2.35",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.35.tgz",
"integrity": "sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==",
"version": "0.2.36",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.36.tgz",
"integrity": "sha512-OPgov0qQiV7wffycylpmEq6rm4Pu68LIMFbB1jrM5bCr1yXqgIMQ6IparbgRuFG5aj3NPmsorrGh7pQJnQlIIw==",
"dependencies": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.14",
@ -1151,15 +1169,6 @@
"node": ">=8"
}
},
"node_modules/figures/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/file-entry-cache": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
@ -1172,6 +1181,14 @@
"node": ">=4"
}
},
"node_modules/filelist": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
"dependencies": {
"minimatch": "^3.0.4"
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@ -1656,6 +1673,79 @@
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"node_modules/jake": {
"version": "10.8.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
"dependencies": {
"async": "0.9.x",
"chalk": "^2.4.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
},
"bin": {
"jake": "bin/cli.js"
},
"engines": {
"node": "*"
}
},
"node_modules/jake/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/jake/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/jake/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/jake/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"node_modules/jake/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"engines": {
"node": ">=4"
}
},
"node_modules/jake/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
@ -1670,6 +1760,11 @@
"node": ">= 10.13.0"
}
},
"node_modules/js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -1715,9 +1810,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/logplease": {
@ -1753,7 +1848,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -1919,15 +2013,6 @@
"node": ">=0.3.1"
}
},
"node_modules/mocha/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/mocha/node_modules/find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
@ -2388,6 +2473,16 @@
"ffjavascript": "0.2.35"
}
},
"node_modules/r1csfile/node_modules/ffjavascript": {
"version": "0.2.35",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.35.tgz",
"integrity": "sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==",
"dependencies": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.14",
"web-worker": "^1.0.0"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -3333,12 +3428,6 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -3570,11 +3659,15 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"big-integer": {
"version": "1.6.48",
@ -3603,7 +3696,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -3701,6 +3793,18 @@
"requires": {
"ffjavascript": "0.2.35",
"fnv-plus": "^1.3.1"
},
"dependencies": {
"ffjavascript": {
"version": "0.2.35",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.35.tgz",
"integrity": "sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==",
"requires": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.14",
"web-worker": "^1.0.0"
}
}
}
},
"cli-cursor": {
@ -3787,8 +3891,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"cross-spawn": {
"version": "6.0.5",
@ -3874,6 +3977,14 @@
"esutils": "^2.0.2"
}
},
"ejs": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
"requires": {
"jake": "^10.6.1"
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@ -3933,6 +4044,11 @@
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
@ -4019,12 +4135,6 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -4180,9 +4290,9 @@
"integrity": "sha512-tz9nWR5KYb6eR2odFQ7oxqEkx8F3YQZ6NBJoJR92YEG3DqYOqyxMck8PKvTVNKx3uwvOqGnLXNScnqpdHRdHGQ=="
},
"ffjavascript": {
"version": "0.2.35",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.35.tgz",
"integrity": "sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==",
"version": "0.2.36",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.36.tgz",
"integrity": "sha512-OPgov0qQiV7wffycylpmEq6rm4Pu68LIMFbB1jrM5bCr1yXqgIMQ6IparbgRuFG5aj3NPmsorrGh7pQJnQlIIw==",
"requires": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.14",
@ -4196,14 +4306,6 @@
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
},
"dependencies": {
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
}
}
},
"file-entry-cache": {
@ -4215,6 +4317,14 @@
"flat-cache": "^2.0.1"
}
},
"filelist": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
"requires": {
"minimatch": "^3.0.4"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@ -4590,6 +4700,63 @@
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"jake": {
"version": "10.8.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
"requires": {
"async": "0.9.x",
"chalk": "^2.4.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
@ -4601,6 +4768,11 @@
"supports-color": "^7.0.0"
}
},
"js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -4640,9 +4812,9 @@
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"logplease": {
@ -4675,7 +4847,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -4810,12 +4981,6 @@
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
@ -5173,6 +5338,18 @@
"@iden3/binfileutils": "0.0.8",
"fastfile": "0.0.19",
"ffjavascript": "0.2.35"
},
"dependencies": {
"ffjavascript": {
"version": "0.2.35",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.35.tgz",
"integrity": "sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==",
"requires": {
"big-integer": "^1.6.48",
"wasmcurves": "0.0.14",
"web-worker": "^1.0.0"
}
}
}
},
"randombytes": {

@ -41,8 +41,10 @@
"@iden3/binfileutils": "0.0.8",
"blake2b-wasm": "https://github.com/jbaylina/blake2b-wasm.git",
"circom_runtime": "0.1.13",
"ejs": "^3.1.6",
"fastfile": "0.0.19",
"ffjavascript": "0.2.35",
"ffjavascript": "0.2.36",
"js-sha3": "^0.8.0",
"logplease": "^1.2.15",
"r1csfile": "0.0.32",
"readline": "^1.3.0"

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
const SUBARRAY_SIZE = 0x40000;
const BigArrayHandler = {

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
/*
import pkg from "../package.json";
const version = pkg.version;

@ -1,3 +1,23 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as fullProve} from "./groth16_fullprove.js";
export {default as prove} from "./groth16_prove.js";
export {default as verify} from "./groth16_verify.js";
export {default as exportSolidityCallData} from "./groth16_exportsoliditycalldata.js";

@ -0,0 +1,42 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
function p256(n) {
let nstr = n.toString(16);
while (nstr.length < 64) nstr = "0"+nstr;
nstr = `"0x${nstr}"`;
return nstr;
}
export default async function groth16ExportSolidityCallData(proof, pub) {
let inputs = "";
for (let i=0; i<pub.length; i++) {
if (inputs != "") inputs = inputs + ",";
inputs = inputs + p256(pub[i]);
}
let S;
S=`[${p256(proof.pi_a[0])}, ${p256(proof.pi_a[1])}],` +
`[[${p256(proof.pi_b[0][1])}, ${p256(proof.pi_b[0][0])}],[${p256(proof.pi_b[1][1])}, ${p256(proof.pi_b[1][0])}]],` +
`[${p256(proof.pi_c[0])}, ${p256(proof.pi_c[1])}],` +
`[${inputs}]`;
return S;
}

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import groth16_prove from "./groth16_prove.js";
import wtns_calculate from "./wtns_calculate.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as zkeyUtils from "./zkey_utils.js";
import * as wtnsUtils from "./wtns_utils.js";
@ -13,7 +32,11 @@ export default async function groth16Prove(zkeyFileName, witnessFileName, logger
const {fd: fdZKey, sections: sectionsZKey} = await binFileUtils.readBinFile(zkeyFileName, "zkey", 2, 1<<25, 1<<23);
const zkey = await zkeyUtils.readHeader(fdZKey, sectionsZKey, "groth16");
const zkey = await zkeyUtils.readHeader(fdZKey, sectionsZKey);
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");
@ -109,6 +132,7 @@ export default async function groth16Prove(zkeyFileName, witnessFileName, logger
proof.pi_c = G1.toObject(G1.toAffine(proof.pi_c));
proof.protocol = "groth16";
proof.curve = curve.name;
await fdZKey.close();
await fdWtns.close();
@ -162,7 +186,7 @@ async function buldABC1(curve, zkey, witness, coeffs, logger) {
}
/*
async function buldABC(curve, zkey, witness, coeffs, logger) {
const concurrency = curve.tm.concurrency;
const sCoef = 4*3 + zkey.n8r;
@ -291,7 +315,7 @@ async function buldABC(curve, zkey, witness, coeffs, logger) {
return 4 + m*sCoef;
}
}
*/
async function joinABC(curve, zkey, a, b, c, logger) {
const MAX_CHUNK_SIZE = 1 << 22;

@ -74,4 +74,4 @@ export default async function groth16Verify(vk_verifier, publicSignals, proof, l
if (logger) logger.info("OK!");
return true;
};
}

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import blake2b from "blake2b-wasm";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as fastFile from "fastfile";
export default async function loadSymbols(symFileName) {

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
/* global window */
import Blake2b from "blake2b-wasm";
import readline from "readline";

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";

24
src/plonk.js Normal file

@ -0,0 +1,24 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as setup} from "./plonk_setup.js";
export {default as fullProve} from "./plonk_fullprove.js";
export {default as prove} from "./plonk_prove.js";
export {default as verify} from "./plonk_verify.js";
export {default as exportSolidityCallData} from "./plonk_exportsoliditycalldata.js";

@ -0,0 +1,68 @@
/*
Copyright 2021 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import { getCurveFromName } from "./curves.js";
function i2hex(i) {
return ("0" + i.toString(16)).slice(-2);
}
function p256(n) {
let nstr = n.toString(16);
while (nstr.length < 64) nstr = "0"+nstr;
nstr = `"0x${nstr}"`;
return nstr;
}
export default async function plonkExportSolidityCallData(proof, pub) {
const curve = await getCurveFromName(proof.curve);
const G1 = curve.G1;
const Fr = curve.Fr;
let inputs = "";
for (let i=0; i<pub.length; i++) {
if (inputs != "") inputs = inputs + ",";
inputs = inputs + p256(pub[i]);
}
const proofBuff = new Uint8Array(G1.F.n8*2*9 + Fr.n8*7);
G1.toRprUncompressed(proofBuff, 0, G1.e(proof.A));
G1.toRprUncompressed(proofBuff, G1.F.n8*2, G1.e(proof.B));
G1.toRprUncompressed(proofBuff, G1.F.n8*4, G1.e(proof.C));
G1.toRprUncompressed(proofBuff, G1.F.n8*6, G1.e(proof.Z));
G1.toRprUncompressed(proofBuff, G1.F.n8*8, G1.e(proof.T1));
G1.toRprUncompressed(proofBuff, G1.F.n8*10, G1.e(proof.T2));
G1.toRprUncompressed(proofBuff, G1.F.n8*12, G1.e(proof.T3));
G1.toRprUncompressed(proofBuff, G1.F.n8*14, G1.e(proof.Wxi));
G1.toRprUncompressed(proofBuff, G1.F.n8*16, G1.e(proof.Wxiw));
Fr.toRprBE(proofBuff, G1.F.n8*18 , Fr.e(proof.eval_a));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8, Fr.e(proof.eval_b));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*2, Fr.e(proof.eval_c));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*3, Fr.e(proof.eval_s1));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*4, Fr.e(proof.eval_s2));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*5, Fr.e(proof.eval_zw));
Fr.toRprBE(proofBuff, G1.F.n8*18 + Fr.n8*6, Fr.e(proof.eval_r));
const proofHex = Array.from(proofBuff).map(i2hex).join("");
const S="0x"+proofHex+",["+inputs+"]";
return S;
}

29
src/plonk_fullprove.js Normal file

@ -0,0 +1,29 @@
/*
Copyright 2021 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import plonk_prove from "./plonk_prove.js";
import wtns_calculate from "./wtns_calculate.js";
export default async function plonkFullProve(input, wasmFile, zkeyFileName, logger) {
const wtns= {
type: "mem"
};
await wtns_calculate(input, wasmFile, wtns);
return await plonk_prove(zkeyFileName, wtns, logger);
}

845
src/plonk_prove.js Normal file

@ -0,0 +1,845 @@
/*
Copyright 2021 0kims association.
This file is part of snarkjs.
snarkjs is a free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
snarkjs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
/* Implementation of this paper: https://eprint.iacr.org/2019/953.pdf section 8.4 */
import * as binFileUtils from "@iden3/binfileutils";
import * as zkeyUtils from "./zkey_utils.js";
import * as wtnsUtils from "./wtns_utils.js";
import { getCurveFromQ as getCurve } from "./curves.js";
import { Scalar, utils, BigBuffer } from "ffjavascript";
const {stringifyBigInts} = utils;
import jsSha3 from "js-sha3";
const { keccak256 } = jsSha3;
export default async function plonk16Prove(zkeyFileName, witnessFileName, logger) {
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);
if (zkey.protocol != "plonk") {
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 -zkey.nAdditions) {
throw new Error(`Invalid witness length. Circuit: ${zkey.nVars}, witness: ${wtns.nWitness}, ${zkey.nAdditions}`);
}
const curve = await getCurve(zkey.q);
const Fr = curve.Fr;
const G1 = curve.G1;
const n8r = curve.Fr.n8;
if (logger) logger.debug("Reading Wtns");
const buffWitness = await binFileUtils.readSection(fdWtns, sectionsWtns, 2);
// First element in plonk is not used and can be any value. (But always the same).
// We set it to zero to go faster in the exponentiations.
buffWitness.set(Fr.zero, 0);
const buffInternalWitness = new BigBuffer(n8r*zkey.nAdditions);
await calculateAdditions();
let A,B,C,Z;
let A4, B4, C4, Z4;
let pol_a,pol_b,pol_c, pol_z, pol_t, pol_r;
let proof = {};
const sigmaBuff = new BigBuffer(zkey.domainSize*n8r*4*3);
let o = sectionsZKey[12][0].p + zkey.domainSize*n8r;
await fdZKey.readToBuffer(sigmaBuff, 0 , zkey.domainSize*n8r*4, o);
o += zkey.domainSize*n8r*5;
await fdZKey.readToBuffer(sigmaBuff, zkey.domainSize*n8r*4 , zkey.domainSize*n8r*4, o);
o += zkey.domainSize*n8r*5;
await fdZKey.readToBuffer(sigmaBuff, zkey.domainSize*n8r*8 , zkey.domainSize*n8r*4, o);
const pol_s1 = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_s1, 0 , zkey.domainSize*n8r, sectionsZKey[12][0].p);
const pol_s2 = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_s2, 0 , zkey.domainSize*n8r, sectionsZKey[12][0].p + 5*zkey.domainSize*n8r);
const PTau = await binFileUtils.readSection(fdZKey, sectionsZKey, 14);
const ch = {};
await round1();
await round2();
await round3();
await round4();
await round5();
///////////////////////
// Final adjustments //
///////////////////////
proof.protocol = "plonk";
proof.curve = curve.name;
await fdZKey.close();
await fdWtns.close();
let publicSignals = [];
for (let i=1; i<= zkey.nPublic; i++) {
const pub = buffWitness.slice(i*Fr.n8, i*Fr.n8+Fr.n8);
publicSignals.push(Scalar.fromRprLE(pub));
}
proof.A = G1.toObject(proof.A);
proof.B = G1.toObject(proof.B);
proof.C = G1.toObject(proof.C);
proof.Z = G1.toObject(proof.Z);
proof.T1 = G1.toObject(proof.T1);
proof.T2 = G1.toObject(proof.T2);
proof.T3 = G1.toObject(proof.T3);
proof.eval_a = Fr.toObject(proof.eval_a);
proof.eval_b = Fr.toObject(proof.eval_b);
proof.eval_c = Fr.toObject(proof.eval_c);
proof.eval_s1 = Fr.toObject(proof.eval_s1);
proof.eval_s2 = Fr.toObject(proof.eval_s2);
proof.eval_zw = Fr.toObject(proof.eval_zw);
proof.eval_t = Fr.toObject(proof.eval_t);
proof.eval_r = Fr.toObject(proof.eval_r);
proof.Wxi = G1.toObject(proof.Wxi);
proof.Wxiw = G1.toObject(proof.Wxiw);
delete proof.eval_t;
proof = stringifyBigInts(proof);
publicSignals = stringifyBigInts(publicSignals);
return {proof, publicSignals};
async function calculateAdditions() {
const additionsBuff = await binFileUtils.readSection(fdZKey, sectionsZKey, 3);
const sSum = 8+curve.Fr.n8*2;
for (let i=0; i<zkey.nAdditions; i++) {
const ai= readUInt32(additionsBuff, i*sSum);
const bi= readUInt32(additionsBuff, i*sSum+4);
const ac= additionsBuff.slice(i*sSum+8, i*sSum+8+n8r);
const bc= additionsBuff.slice(i*sSum+8+n8r, i*sSum+8+n8r*2);
const aw= getWitness(ai);
const bw= getWitness(bi);
const r = curve.Fr.add(
curve.Fr.mul(ac, aw),
curve.Fr.mul(bc, bw)
);
buffInternalWitness.set(r, n8r*i);
}
}
async function buildABC() {
let A = new BigBuffer(zkey.domainSize * n8r);
let B = new BigBuffer(zkey.domainSize * n8r);
let C = new BigBuffer(zkey.domainSize * n8r);
const aMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 4);
const bMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 5);
const cMap = await binFileUtils.readSection(fdZKey, sectionsZKey, 6);
for (let i=0; i<zkey.nConstrains; i++) {
const iA = readUInt32(aMap, i*4);
A.set(getWitness(iA), i*n8r);
const iB = readUInt32(bMap, i*4);
B.set(getWitness(iB), i*n8r);
const iC = readUInt32(cMap, i*4);
C.set(getWitness(iC), i*n8r);
}
A = await Fr.batchToMontgomery(A);
B = await Fr.batchToMontgomery(B);
C = await Fr.batchToMontgomery(C);
return [A,B,C];
}
function readUInt32(b, o) {
const buff = b.slice(o, o+4);
const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength);
return buffV.getUint32(0, true);
}
function getWitness(idx) {
if (idx < zkey.nVars-zkey.nAdditions) {
return buffWitness.slice(idx*n8r, idx*n8r+n8r);
} else if (idx < zkey.nVars) {
return buffInternalWitness.slice((idx - (zkey.nVars-zkey.nAdditions))*n8r, (idx-(zkey.nVars-zkey.nAdditions))*n8r + n8r);
} else {
return curve.Fr.zero;
}
}
async function round1() {
ch.b = [];
for (let i=1; i<=9; i++) {
ch.b[i] = curve.Fr.random();
}
[A, B, C] = await buildABC();
[pol_a, A4] = await to4T(A, [ch.b[2], ch.b[1]]);
[pol_b, B4] = await to4T(B, [ch.b[4], ch.b[3]]);
[pol_c, C4] = await to4T(C, [ch.b[6], ch.b[5]]);
proof.A = await expTau(pol_a, "multiexp A");
proof.B = await expTau(pol_b, "multiexp B");
proof.C = await expTau(pol_c, "multiexp C");
}
async function round2() {
const transcript1 = new Uint8Array(G1.F.n8*2*3);
G1.toRprUncompressed(transcript1, 0, proof.A);
G1.toRprUncompressed(transcript1, G1.F.n8*2, proof.B);
G1.toRprUncompressed(transcript1, G1.F.n8*4, proof.C);
ch.beta = hashToFr(transcript1);
if (logger) logger.debug("beta: " + Fr.toString(ch.beta));
const transcript2 = new Uint8Array(n8r);
Fr.toRprBE(transcript2, 0, ch.beta);
ch.gamma = hashToFr(transcript2);
if (logger) logger.debug("gamma: " + Fr.toString(ch.gamma));
let numArr = new BigBuffer(Fr.n8*zkey.domainSize);
let denArr = new BigBuffer(Fr.n8*zkey.domainSize);
numArr.set(Fr.one, 0);
denArr.set(Fr.one, 0);
let w = Fr.one;
for (let i=0; i<zkey.domainSize; i++) {
let n1 = A.slice(i*n8r, (i+1)*n8r);
n1 = Fr.add( n1, Fr.mul(ch.beta, w) );
n1 = Fr.add( n1, ch.gamma );
let n2 = B.slice(i*n8r, (i+1)*n8r);
n2 = Fr.add( n2, Fr.mul(zkey.k1, Fr.mul(ch.beta, w) ));
n2 = Fr.add( n2, ch.gamma );
let n3 = C.slice(i*n8r, (i+1)*n8r);
n3 = Fr.add( n3, Fr.mul(zkey.k2, Fr.mul(ch.beta, w) ));
n3 = Fr.add( n3, ch.gamma );
const num = Fr.mul(n1, Fr.mul(n2, n3));
let d1 = A.slice(i*n8r, (i+1)*n8r);
d1 = Fr.add(d1, Fr.mul( sigmaBuff.slice(i*n8r*4, i*n8r*4 + n8r) , ch.beta));
d1 = Fr.add(d1, ch.gamma);
let d2 = B.slice(i*n8r, (i+1)*n8r);
d2 = Fr.add(d2, Fr.mul( sigmaBuff.slice((zkey.domainSize + i)*4*n8r, (zkey.domainSize + i)*4*n8r+n8r) , ch.beta));
d2 = Fr.add(d2, ch.gamma);
let d3 = C.slice(i*n8r, (i+1)*n8r);
d3 = Fr.add(d3, Fr.mul( sigmaBuff.slice((zkey.domainSize*2 + i)*4*n8r, (zkey.domainSize*2 + i)*4*n8r + n8r) , ch.beta));
d3 = Fr.add(d3, ch.gamma);
const den = Fr.mul(d1, Fr.mul(d2, d3));
numArr.set(
Fr.mul(
numArr.slice(i*n8r,(i+1)*n8r) ,
num
),
((i+1)%zkey.domainSize)*n8r
);
denArr.set(
Fr.mul(
denArr.slice(i*n8r,(i+1)*n8r) ,
den
),
((i+1)%zkey.domainSize)*n8r
);
w = Fr.mul(w, Fr.w[zkey.power]);
}
denArr = await Fr.batchInverse(denArr);
// TODO: Do it in assembly and in parallel
for (let i=0; i<zkey.domainSize; i++) {
numArr.set( Fr.mul( numArr.slice(i*n8r, (i+1)*n8r), denArr.slice(i*n8r, (i+1)*n8r) ) ,i*n8r);
}
if (!Fr.eq(numArr.slice(0, n8r), Fr.one)) {
throw new Error("Copy constraints does not match");
}
Z = numArr;
[pol_z, Z4] = await to4T(Z, [ch.b[9], ch.b[8], ch.b[7]]);
proof.Z = await expTau( pol_z, "multiexp Z");
}
async function round3() {
/*
async function checkDegree(P) {
const p = await curve.Fr.ifft(P);
let deg = (P.byteLength/n8r)-1;
while ((deg>0)&&(Fr.isZero(p.slice(deg*n8r, deg*n8r+n8r)))) deg--;
return deg;
}
function printPol(P) {
const n=(P.byteLength/n8r);
console.log("[");
for (let i=0; i<n; i++) {
console.log(Fr.toString(P.slice(i*n8r, i*n8r+n8r)));
}
console.log("]");
}
*/
const QM4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QM4, 0 , zkey.domainSize*n8r*4, sectionsZKey[7][0].p + zkey.domainSize*n8r);
const QL4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QL4, 0 , zkey.domainSize*n8r*4, sectionsZKey[8][0].p + zkey.domainSize*n8r);
const QR4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QR4, 0 , zkey.domainSize*n8r*4, sectionsZKey[9][0].p + zkey.domainSize*n8r);
const QO4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QO4, 0 , zkey.domainSize*n8r*4, sectionsZKey[10][0].p + zkey.domainSize*n8r);
const QC4 = new BigBuffer(zkey.domainSize*4*n8r);
await fdZKey.readToBuffer(QC4, 0 , zkey.domainSize*n8r*4, sectionsZKey[11][0].p + zkey.domainSize*n8r);
const lPols = await binFileUtils.readSection(fdZKey, sectionsZKey, 13);
const transcript3 = new Uint8Array(G1.F.n8*2);
G1.toRprUncompressed(transcript3, 0, proof.Z);
ch.alpha = hashToFr(transcript3);
if (logger) logger.debug("alpha: " + Fr.toString(ch.alpha));
const Z1 = [
Fr.zero,
Fr.add(Fr.e(-1), Fr.w[2]),
Fr.e(-2),
Fr.sub(Fr.e(-1), Fr.w[2]),
];
const Z2 = [
Fr.zero,
Fr.add(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])),
Fr.e(4),
Fr.sub(Fr.zero, Fr.mul(Fr.e(-2), Fr.w[2])),
];
const Z3 = [
Fr.zero,
Fr.add(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])),
Fr.e(-8),
Fr.sub(Fr.e(2), Fr.mul(Fr.e(2), Fr.w[2])),
];
const T = new BigBuffer(zkey.domainSize*4*n8r);
const Tz = new BigBuffer(zkey.domainSize*4*n8r);
let w = Fr.one;
for (let i=0; i<zkey.domainSize*4; i++) {
const a = A4.slice(i*n8r, i*n8r+n8r);
const b = B4.slice(i*n8r, i*n8r+n8r);
const c = C4.slice(i*n8r, i*n8r+n8r);
const z = Z4.slice(i*n8r, i*n8r+n8r);
const zw = Z4.slice(((i+zkey.domainSize*4+4)%(zkey.domainSize*4)) *n8r, ((i+zkey.domainSize*4+4)%(zkey.domainSize*4)) *n8r +n8r);
const qm = QM4.slice(i*n8r, i*n8r+n8r);
const ql = QL4.slice(i*n8r, i*n8r+n8r);
const qr = QR4.slice(i*n8r, i*n8r+n8r);
const qo = QO4.slice(i*n8r, i*n8r+n8r);
const qc = QC4.slice(i*n8r, i*n8r+n8r);
const s1 = sigmaBuff.slice(i*n8r, i*n8r+n8r);
const s2 = sigmaBuff.slice((i+zkey.domainSize*4)*n8r, (i+zkey.domainSize*4)*n8r+n8r);
const s3 = sigmaBuff.slice((i+zkey.domainSize*8)*n8r, (i+zkey.domainSize*8)*n8r+n8r);
const ap = Fr.add(ch.b[2], Fr.mul(ch.b[1], w));
const bp = Fr.add(ch.b[4], Fr.mul(ch.b[3], w));
const cp = Fr.add(ch.b[6], Fr.mul(ch.b[5], w));
const w2 = Fr.square(w);
const zp = Fr.add(Fr.add(Fr.mul(ch.b[7], w2), Fr.mul(ch.b[8], w)), ch.b[9]);
const wW = Fr.mul(w, Fr.w[zkey.power]);
const wW2 = Fr.square(wW);
const zWp = Fr.add(Fr.add(Fr.mul(ch.b[7], wW2), Fr.mul(ch.b[8], wW)), ch.b[9]);
let pl = Fr.zero;
for (let j=0; j<zkey.nPublic; j++) {
pl = Fr.sub(pl, Fr.mul(
lPols.slice( (j*5*zkey.domainSize+ zkey.domainSize+ i)*n8r, (j*5*zkey.domainSize+ zkey.domainSize + i+1)*n8r),
A.slice(j*n8r, (j+1)*n8r)
));
}
let [e1, e1z] = mul2(a, b, ap, bp, i%4);
e1 = Fr.mul(e1, qm);
e1z = Fr.mul(e1z, qm);
e1 = Fr.add(e1, Fr.mul(a, ql));
e1z = Fr.add(e1z, Fr.mul(ap, ql));
e1 = Fr.add(e1, Fr.mul(b, qr));
e1z = Fr.add(e1z, Fr.mul(bp, qr));
e1 = Fr.add(e1, Fr.mul(c, qo));
e1z = Fr.add(e1z, Fr.mul(cp, qo));
e1 = Fr.add(e1, pl);
e1 = Fr.add(e1, qc);
const betaw = Fr.mul(ch.beta, w);
let e2a =a;
e2a = Fr.add(e2a, betaw);
e2a = Fr.add(e2a, ch.gamma);
let e2b =b;
e2b = Fr.add(e2b, Fr.mul(betaw, zkey.k1));
e2b = Fr.add(e2b, ch.gamma);
let e2c =c;
e2c = Fr.add(e2c, Fr.mul(betaw, zkey.k2));
e2c = Fr.add(e2c, ch.gamma);
let e2d = z;
let [e2, e2z] = mul4(e2a, e2b, e2c, e2d, ap, bp, cp, zp, i%4);
e2 = Fr.mul(e2, ch.alpha);
e2z = Fr.mul(e2z, ch.alpha);
let e3a = a;
e3a = Fr.add(e3a, Fr.mul(ch.beta, s1));
e3a = Fr.add(e3a, ch.gamma);
let e3b = b;
e3b = Fr.add(e3b, Fr.mul(ch.beta,s2));
e3b = Fr.add(e3b, ch.gamma);
let e3c = c;
e3c = Fr.add(e3c, Fr.mul(ch.beta,s3));
e3c = Fr.add(e3c, ch.gamma);
let e3d = zw;
let [e3, e3z] = mul4(e3a, e3b, e3c, e3d, ap, bp, cp, zWp, i%4);
e3 = Fr.mul(e3, ch.alpha);
e3z = Fr.mul(e3z, ch.alpha);
let e4 = Fr.sub(z, Fr.one);
e4 = Fr.mul(e4, lPols.slice( (zkey.domainSize + i)*n8r, (zkey.domainSize+i+1)*n8r));
e4 = Fr.mul(e4, Fr.mul(ch.alpha, ch.alpha));
let e4z = Fr.mul(zp, lPols.slice( (zkey.domainSize + i)*n8r, (zkey.domainSize+i+1)*n8r));
e4z = Fr.mul(e4z, Fr.mul(ch.alpha, ch.alpha));
let e = Fr.add(Fr.sub(Fr.add(e1, e2), e3), e4);
let ez = Fr.add(Fr.sub(Fr.add(e1z, e2z), e3z), e4z);
T.set(e, i*n8r);
Tz.set(ez, i*n8r);
w = Fr.mul(w, Fr.w[zkey.power+2]);
}
let t = await Fr.ifft(T);
for (let i=0; i<zkey.domainSize; i++) {
t.set(Fr.neg(t.slice(i*n8r, i*n8r+n8r)), i*n8r);
}
for (let i=zkey.domainSize; i<zkey.domainSize*4; i++) {
const a = Fr.sub(
t.slice((i-zkey.domainSize)*n8r, (i-zkey.domainSize)*n8r + n8r),
t.slice(i*n8r, i*n8r+n8r)
);
t.set(a, i*n8r);
if (i > (zkey.domainSize*3 -4) ) {
if (!Fr.isZero(a)) {
throw new Error("T Polynomial is not divisible");
}
}
}
const tz = await Fr.ifft(Tz);
for (let i=0; i<zkey.domainSize*4; i++) {
const a = tz.slice(i*n8r, (i+1)*n8r);
if (i > (zkey.domainSize*3 +5) ) {
if (!Fr.isZero(a)) {
throw new Error("Tz Polynomial is not well calculated");
}
} else {
t.set(
Fr.add(
t.slice(i*n8r, (i+1)*n8r),
a
),
i*n8r
);
}
}
pol_t = t.slice(0, (zkey.domainSize*3+6)*n8r);
proof.T1 = await expTau( t.slice(0, zkey.domainSize*n8r) , "multiexp T1");
proof.T2 = await expTau( t.slice(zkey.domainSize*n8r, zkey.domainSize*2*n8r) , "multiexp T2");
proof.T3 = await expTau( t.slice(zkey.domainSize*2*n8r, (zkey.domainSize*3+6)*n8r) , "multiexp T3");
function mul2(a,b, ap, bp, p) {
let r, rz;
const a_b = Fr.mul(a,b);
const a_bp = Fr.mul(a,bp);
const ap_b = Fr.mul(ap,b);
const ap_bp = Fr.mul(ap,bp);
r = a_b;
let a0 = Fr.add(a_bp, ap_b);
let a1 = ap_bp;
rz = a0;
if (p) {
rz = Fr.add(rz, Fr.mul(Z1[p], a1));
}
return [r, rz];
}
function mul4(a,b,c,d, ap, bp, cp, dp, p) {
let r, rz;
const a_b = Fr.mul(a,b);
const a_bp = Fr.mul(a,bp);
const ap_b = Fr.mul(ap,b);
const ap_bp = Fr.mul(ap,bp);
const c_d = Fr.mul(c,d);
const c_dp = Fr.mul(c,dp);
const cp_d = Fr.mul(cp,d);
const cp_dp = Fr.mul(cp,dp);
r = Fr.mul(a_b, c_d);
let a0 = Fr.mul(ap_b, c_d);
a0 = Fr.add(a0, Fr.mul(a_bp, c_d));
a0 = Fr.add(a0, Fr.mul(a_b, cp_d));
a0 = Fr.add(a0, Fr.mul(a_b, c_dp));
let a1 = Fr.mul(ap_bp, c_d);
a1 = Fr.add(a1, Fr.mul(ap_b, cp_d));
a1 = Fr.add(a1, Fr.mul(ap_b, c_dp));
a1 = Fr.add(a1, Fr.mul(a_bp, cp_d));
a1 = Fr.add(a1, Fr.mul(a_bp, c_dp));
a1 = Fr.add(a1, Fr.mul(a_b, cp_dp));
let a2 = Fr.mul(a_bp, cp_dp);
a2 = Fr.add(a2, Fr.mul(ap_b, cp_dp));
a2 = Fr.add(a2, Fr.mul(ap_bp, c_dp));
a2 = Fr.add(a2, Fr.mul(ap_bp, cp_d));
let a3 = Fr.mul(ap_bp, cp_dp);
rz = a0;
if (p) {
rz = Fr.add(rz, Fr.mul(Z1[p], a1));
rz = Fr.add(rz, Fr.mul(Z2[p], a2));
rz = Fr.add(rz, Fr.mul(Z3[p], a3));
}
return [r, rz];
}
}
async function round4() {
const pol_qm = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qm, 0 , zkey.domainSize*n8r, sectionsZKey[7][0].p);
const pol_ql = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_ql, 0 , zkey.domainSize*n8r, sectionsZKey[8][0].p);
const pol_qr = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qr, 0 , zkey.domainSize*n8r, sectionsZKey[9][0].p);
const pol_qo = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qo, 0 , zkey.domainSize*n8r, sectionsZKey[10][0].p);
const pol_qc = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_qc, 0 , zkey.domainSize*n8r, sectionsZKey[11][0].p);
const pol_s3 = new BigBuffer(zkey.domainSize*n8r);
await fdZKey.readToBuffer(pol_s3, 0 , zkey.domainSize*n8r, sectionsZKey[12][0].p + 10*zkey.domainSize*n8r);
const transcript4 = new Uint8Array(G1.F.n8*2*3);
G1.toRprUncompressed(transcript4, 0, proof.T1);
G1.toRprUncompressed(transcript4, G1.F.n8*2, proof.T2);
G1.toRprUncompressed(transcript4, G1.F.n8*4, proof.T3);
ch.xi = hashToFr(transcript4);
if (logger) logger.debug("xi: " + Fr.toString(ch.xi));
proof.eval_a = evalPol(pol_a, ch.xi);
proof.eval_b = evalPol(pol_b, ch.xi);
proof.eval_c = evalPol(pol_c, ch.xi);
proof.eval_s1 = evalPol(pol_s1, ch.xi);
proof.eval_s2 = evalPol(pol_s2, ch.xi);
proof.eval_t = evalPol(pol_t, ch.xi);
proof.eval_zw = evalPol(pol_z, Fr.mul(ch.xi, Fr.w[zkey.power]));
const coef_ab = Fr.mul(proof.eval_a, proof.eval_b);
let e2a = proof.eval_a;
const betaxi = Fr.mul(ch.beta, ch.xi);
e2a = Fr.add( e2a, betaxi);
e2a = Fr.add( e2a, ch.gamma);
let e2b = proof.eval_b;
e2b = Fr.add( e2b, Fr.mul(betaxi, zkey.k1));
e2b = Fr.add( e2b, ch.gamma);
let e2c = proof.eval_c;
e2c = Fr.add( e2c, Fr.mul(betaxi, zkey.k2));
e2c = Fr.add( e2c, ch.gamma);
const e2 = Fr.mul(Fr.mul(Fr.mul(e2a, e2b), e2c), ch.alpha);
let e3a = proof.eval_a;
e3a = Fr.add( e3a, Fr.mul(ch.beta, proof.eval_s1));
e3a = Fr.add( e3a, ch.gamma);
let e3b = proof.eval_b;
e3b = Fr.add( e3b, Fr.mul(ch.beta, proof.eval_s2));
e3b = Fr.add( e3b, ch.gamma);
let e3 = Fr.mul(e3a, e3b);
e3 = Fr.mul(e3, ch.beta);
e3 = Fr.mul(e3, proof.eval_zw);
e3 = Fr.mul(e3, ch.alpha);
ch.xim= ch.xi;
for (let i=0; i<zkey.power; i++) ch.xim = Fr.mul(ch.xim, ch.xim);
const eval_l1 = Fr.div(
Fr.sub(ch.xim, Fr.one),
Fr.mul(Fr.sub(ch.xi, Fr.one), Fr.e(zkey.domainSize))
);
const e4 = Fr.mul(eval_l1, Fr.mul(ch.alpha, ch.alpha));
const coefs3 = e3;
const coefz = Fr.add(e2, e4);
pol_r = new BigBuffer((zkey.domainSize+3)*n8r);
for (let i = 0; i<zkey.domainSize+3; i++) {
let v = Fr.mul(coefz, pol_z.slice(i*n8r,(i+1)*n8r));
if (i<zkey.domainSize) {
v = Fr.add(v, Fr.mul(coef_ab, pol_qm.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, Fr.mul(proof.eval_a, pol_ql.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, Fr.mul(proof.eval_b, pol_qr.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, Fr.mul(proof.eval_c, pol_qo.slice(i*n8r,(i+1)*n8r)));
v = Fr.add(v, pol_qc.slice(i*n8r,(i+1)*n8r));
v = Fr.sub(v, Fr.mul(coefs3, pol_s3.slice(i*n8r,(i+1)*n8r)));
}
pol_r.set(v, i*n8r);
}
proof.eval_r = evalPol(pol_r, ch.xi);
}
async function round5() {
const transcript5 = new Uint8Array(n8r*7);
Fr.toRprBE(transcript5, 0, proof.eval_a);
Fr.toRprBE(transcript5, n8r, proof.eval_b);
Fr.toRprBE(transcript5, n8r*2, proof.eval_c);
Fr.toRprBE(transcript5, n8r*3, proof.eval_s1);
Fr.toRprBE(transcript5, n8r*4, proof.eval_s2);
Fr.toRprBE(transcript5, n8r*5, proof.eval_zw);
Fr.toRprBE(transcript5, n8r*6, proof.eval_r);
ch.v = [];
ch.v[1] = hashToFr(transcript5);
if (logger) logger.debug("v: " + Fr.toString(ch.v[1]));
for (let i=2; i<=6; i++ ) ch.v[i] = Fr.mul(ch.v[i-1], ch.v[1]);
let pol_wxi = new BigBuffer((zkey.domainSize+6)*n8r);
const xi2m = Fr.mul(ch.xim, ch.xim);
for (let i=0; i<zkey.domainSize+6; i++) {
let w = Fr.zero;
w = Fr.add(w, Fr.mul(xi2m, pol_t.slice( (zkey.domainSize*2+i)*n8r, (zkey.domainSize*2+i+1)*n8r )));
if (i<zkey.domainSize+3) {
w = Fr.add(w, Fr.mul(ch.v[1], pol_r.slice(i*n8r, (i+1)*n8r)));
}
if (i<zkey.domainSize+2) {
w = Fr.add(w, Fr.mul(ch.v[2], pol_a.slice(i*n8r, (i+1)*n8r)));
w = Fr.add(w, Fr.mul(ch.v[3], pol_b.slice(i*n8r, (i+1)*n8r)));
w = Fr.add(w, Fr.mul(ch.v[4], pol_c.slice(i*n8r, (i+1)*n8r)));
}
if (i<zkey.domainSize) {
w = Fr.add(w, pol_t.slice(i*n8r, (i+1)*n8r));
w = Fr.add(w, Fr.mul(ch.xim, pol_t.slice( (zkey.domainSize+i)*n8r, (zkey.domainSize+i+1)*n8r )));
w = Fr.add(w, Fr.mul(ch.v[5], pol_s1.slice(i*n8r, (i+1)*n8r)));
w = Fr.add(w, Fr.mul(ch.v[6], pol_s2.slice(i*n8r, (i+1)*n8r)));
}
pol_wxi.set(w, i*n8r);
}
let w0 = pol_wxi.slice(0, n8r);
w0 = Fr.sub(w0, proof.eval_t);
w0 = Fr.sub(w0, Fr.mul(ch.v[1], proof.eval_r));
w0 = Fr.sub(w0, Fr.mul(ch.v[2], proof.eval_a));
w0 = Fr.sub(w0, Fr.mul(ch.v[3], proof.eval_b));
w0 = Fr.sub(w0, Fr.mul(ch.v[4], proof.eval_c));
w0 = Fr.sub(w0, Fr.mul(ch.v[5], proof.eval_s1));
w0 = Fr.sub(w0, Fr.mul(ch.v[6], proof.eval_s2));
pol_wxi.set(w0, 0);
pol_wxi= divPol1(pol_wxi, ch.xi);
proof.Wxi = await expTau(pol_wxi, "multiexp Wxi");
let pol_wxiw = new BigBuffer((zkey.domainSize+3)*n8r);
for (let i=0; i<zkey.domainSize+3; i++) {
const w = pol_z.slice(i*n8r, (i+1)*n8r);
pol_wxiw.set(w, i*n8r);
}
w0 = pol_wxiw.slice(0, n8r);
w0 = Fr.sub(w0, proof.eval_zw);
pol_wxiw.set(w0, 0);
pol_wxiw= divPol1(pol_wxiw, Fr.mul(ch.xi, Fr.w[zkey.power]));
proof.Wxiw = await expTau(pol_wxiw, "multiexp Wxiw");
}
function hashToFr(transcript) {
const v = Scalar.fromRprBE(new Uint8Array(keccak256.arrayBuffer(transcript)));
return Fr.e(v);
}
function evalPol(P, x) {
const n = P.byteLength / n8r;
if (n == 0) return Fr.zero;
let res = P.slice((n-1)*n8r, n*n8r);
for (let i=n-2; i>=0; i--) {
res = Fr.add(Fr.mul(res, x), P.slice(i*n8r, (i+1)*n8r));
}
return res;
}
function divPol1(P, d) {
const n = P.byteLength/n8r;
const res = new BigBuffer(n*n8r);
res.set(Fr.zero, (n-1) *n8r);
res.set(P.slice((n-1)*n8r, n*n8r), (n-2)*n8r);
for (let i=n-3; i>=0; i--) {
res.set(
Fr.add(
P.slice((i+1)*n8r, (i+2)*n8r),
Fr.mul(
d,
res.slice((i+1)*n8r, (i+2)*n8r)
)
),
i*n8r
);
}
if (!Fr.eq(
P.slice(0, n8r),
Fr.mul(
Fr.neg(d),
res.slice(0, n8r)
)
)) {
throw new Error("Polinomial does not divide");
}
return res;
}
async function expTau(b, name) {
const n = b.byteLength/n8r;
const PTauN = PTau.slice(0, n*curve.G1.F.n8*2);
const bm = await curve.Fr.batchFromMontgomery(b);
let res = await curve.G1.multiExpAffine(PTauN, bm, logger, name);
res = curve.G1.toAffine(res);
return res;
}
async function to4T(A, pz) {
pz = pz || [];
let a = await Fr.ifft(A);
const a4 = new BigBuffer(n8r*zkey.domainSize*4);
a4.set(a, 0);
const a1 = new BigBuffer(n8r*(zkey.domainSize + pz.length));
a1.set(a, 0);
for (let i= 0; i<pz.length; i++) {
a1.set(
Fr.add(
a1.slice((zkey.domainSize+i)*n8r, (zkey.domainSize+i+1)*n8r),
pz[i]
),
(zkey.domainSize+i)*n8r
);
a1.set(
Fr.sub(
a1.slice(i*n8r, (i+1)*n8r),
pz[i]
),
i*n8r
);
}
const A4 = await Fr.fft(a4);
return [a1, A4];
}
}

422
src/plonk_setup.js Normal file

@ -0,0 +1,422 @@
/*
Copyright 2021 0kims association.
This file is part of snarkjs.
snarkjs is a free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
snarkjs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
/* Implementation of this paper: https://eprint.iacr.org/2019/953.pdf */
import {readR1csHeader} from "r1csfile";
import * as utils from "./powersoftau_utils.js";
import {
readBinFile,
createBinFile,
readSection,
writeBigInt,
startWriteSection,
endWriteSection,
} from "@iden3/binfileutils";
import { log2 } from "./misc.js";
import { Scalar, BigBuffer } from "ffjavascript";
import Blake2b from "blake2b-wasm";
import BigArray from "./bigarray.js";
export default async function plonkSetup(r1csName, ptauName, zkeyName, logger) {
await Blake2b.ready();
const {fd: fdPTau, sections: sectionsPTau} = await readBinFile(ptauName, "ptau", 1, 1<<22, 1<<24);
const {curve, power} = await utils.readPTauHeader(fdPTau, sectionsPTau);
const {fd: fdR1cs, sections: sectionsR1cs} = await readBinFile(r1csName, "r1cs", 1, 1<<22, 1<<24);
const r1cs = await readR1csHeader(fdR1cs, sectionsR1cs, false);
const sG1 = curve.G1.F.n8*2;
const G1 = curve.G1;
const sG2 = curve.G2.F.n8*2;
const Fr = curve.Fr;
const n8r = curve.Fr.n8;
if (logger) logger.info("Reading r1cs");
let sR1cs = await readSection(fdR1cs, sectionsR1cs, 2);
const plonkConstraints = new BigArray();
const plonkAdditions = new BigArray();
let plonkNVars = r1cs.nVars;
const nPublic = r1cs.nOutputs + r1cs.nPubInputs;
await processConstraints();
const fdZKey = await createBinFile(zkeyName, "zkey", 1, 14, 1<<22, 1<<24);
if (r1cs.prime != curve.r) {
if (logger) logger.error("r1cs curve does not match powers of tau ceremony curve");
return -1;
}
const cirPower = log2(plonkConstraints.length -1) +1;
const domainSize = 2 ** cirPower;
if (cirPower > power) {
if (logger) logger.error(`circuit too big for this power of tau ceremony. ${r1cs.nConstraints}*2 > 2**${power}`);
return -1;
}
if (!sectionsPTau[12]) {
if (logger) logger.error("Powers of tau is not prepared.");
return -1;
}
const LPoints = new BigBuffer(domainSize*sG1);
const o = sectionsPTau[12][0].p + ((2 ** (cirPower)) -1)*sG1;
await fdPTau.readToBuffer(LPoints, 0, domainSize*sG1, o);
const [k1, k2] = getK1K2();
const vk = {};
await writeAdditions(3, "Additions");
await writeWitnessMap(4, 0, "Amap");
await writeWitnessMap(5, 1, "Bmap");
await writeWitnessMap(6, 2, "Cmap");
await writeQMap(7, 3, "Qm");
await writeQMap(8, 4, "Ql");
await writeQMap(9, 5, "Qr");
await writeQMap(10, 6, "Qo");
await writeQMap(11, 7, "Qc");
await writeSigma(12, "sigma");
await writeLs(13, "lagrange polynomials");
// Write PTau points
////////////
await startWriteSection(fdZKey, 14);
const buffOut = new BigBuffer((domainSize+6)*sG1);
await fdPTau.readToBuffer(buffOut, 0, (domainSize+6)*sG1, sectionsPTau[2][0].p);
await fdZKey.write(buffOut);
await endWriteSection(fdZKey);
await writeHeaders();
await fdZKey.close();
await fdR1cs.close();
await fdPTau.close();
if (logger) logger.info("Setup Finished");
return ;
async function processConstraints() {
let r1csPos = 0;
function r1cs_readULE32() {
const buff = sR1cs.slice(r1csPos, r1csPos+4);
r1csPos += 4;
const buffV = new DataView(buff.buffer);
return buffV.getUint32(0, true);
}
function r1cs_readCoef() {
const res = Fr.fromRprLE(sR1cs.slice(r1csPos, r1csPos+curve.Fr.n8));
r1csPos += curve.Fr.n8;
return res;
}
function r1cs_readCoefs() {
const coefs = [];
const res = {
k: curve.Fr.zero
};
const nA = r1cs_readULE32();
for (let i=0; i<nA; i++) {
const s = r1cs_readULE32();
const coefp = r1cs_readCoef();
if (s==0) {
res.k = coefp;
} else {
coefs.push([s, coefp]);
}
}
const resCoef = reduceCoef(coefs);
res.s = resCoef[0];
res.coef = resCoef[1];
return res;
}
function reduceCoef(coefs) {
if (coefs.length == 0) {
return [0, curve.Fr.zero];
}
if (coefs.length == 1) {
return coefs[0];
}
const arr1 = coefs.slice(0, coefs.length >> 1);
const arr2 = coefs.slice(coefs.length >> 1);
const coef1 = reduceCoef(arr1);
const coef2 = reduceCoef(arr2);
const sl = coef1[0];
const sr = coef2[0];
const so = plonkNVars++;
const qm = curve.Fr.zero;
const ql = Fr.neg(coef1[1]);
const qr = Fr.neg(coef2[1]);
const qo = curve.Fr.one;
const qc = curve.Fr.zero;
plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]);
plonkAdditions.push([sl, sr, coef1[1], coef2[1]]);
return [so, curve.Fr.one];
}
for (let s = 1; s <= nPublic ; s++) {
const sl = s;
const sr = 0;
const so = 0;
const qm = curve.Fr.zero;
const ql = curve.Fr.one;
const qr = curve.Fr.zero;
const qo = curve.Fr.zero;
const qc = curve.Fr.zero;
plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]);
}
for (let c=0; c<r1cs.nConstraints; c++) {
if ((logger)&&(c%10000 == 0)) logger.debug(`processing constraints: ${c}/${r1cs.nConstraints}`);
const A = r1cs_readCoefs();
const B = r1cs_readCoefs();
const C = r1cs_readCoefs();
const sl = A.s;
const sr = B.s;
const so = C.s;
const qm = curve.Fr.mul(A.coef, B.coef);
const ql = curve.Fr.mul(A.coef, B.k);
const qr = curve.Fr.mul(A.k, B.coef);
const qo = curve.Fr.neg(C.coef);
const qc = curve.Fr.neg(C.k);
plonkConstraints.push([sl, sr, so, qm, ql, qr, qo, qc]);
}
}
async function writeWitnessMap(sectionNum, posConstraint, name) {
await startWriteSection(fdZKey, sectionNum);
for (let i=0; i<plonkConstraints.length; i++) {
await fdZKey.writeULE32(plonkConstraints[i][posConstraint]);
if ((logger)&&(i%1000000 == 0)) logger.debug(`writing ${name}: ${i}/${plonkConstraints.length}`);
}
await endWriteSection(fdZKey);
}
async function writeQMap(sectionNum, posConstraint, name) {
let Q = new BigBuffer(domainSize*n8r);
for (let i=0; i<plonkConstraints.length; i++) {
Q.set(plonkConstraints[i][posConstraint], i*n8r);
if ((logger)&&(i%1000000 == 0)) logger.debug(`writing ${name}: ${i}/${plonkConstraints.length}`);
}
await startWriteSection(fdZKey, sectionNum);
await writeP4(Q);
await endWriteSection(fdZKey);
Q = await Fr.batchFromMontgomery(Q);
vk[name]= await curve.G1.multiExpAffine(LPoints, Q, logger, "multiexp "+name);
}
async function writeP4(buff) {
const q = await Fr.ifft(buff);
const q4 = new BigBuffer(domainSize*n8r*4);
q4.set(q, 0);
const Q4 = await Fr.fft(q4);
await fdZKey.write(q);
await fdZKey.write(Q4);
}
async function writeAdditions(sectionNum, name) {
await startWriteSection(fdZKey, sectionNum);
const buffOut = new Uint8Array((2*4+2*n8r));
const buffOutV = new DataView(buffOut.buffer);
for (let i=0; i<plonkAdditions.length; i++) {
const addition=plonkAdditions[i];
let o=0;
buffOutV.setUint32(o, addition[0], true); o+=4;
buffOutV.setUint32(o, addition[1], true); o+=4;
// The value is storen in Montgomery. stored = v*R
// so when montgomery multiplicated by the witness it result = v*R*w/R = v*w
buffOut.set(addition[2], o); o+= n8r;
buffOut.set(addition[3], o); o+= n8r;
await fdZKey.write(buffOut);
if ((logger)&&(i%1000000 == 0)) logger.debug(`writing ${name}: ${i}/${plonkAdditions.length}`);
}
await endWriteSection(fdZKey);
}
async function writeSigma(sectionNum, name) {
const sigma = new BigBuffer(n8r*domainSize*3);
const lastAparence = new BigArray(plonkNVars);
const firstPos = new BigArray(plonkNVars);
let w = Fr.one;
for (let i=0; i<domainSize;i++) {
if (i<plonkConstraints.length) {
buildSigma(plonkConstraints[i][0], i);
buildSigma(plonkConstraints[i][1], domainSize + i);
buildSigma(plonkConstraints[i][2], domainSize*2 + i);
} else {
buildSigma(0, i);
buildSigma(0, domainSize + i);
buildSigma(0, domainSize*2 + i);
}
w = Fr.mul(w, Fr.w[cirPower]);
if ((logger)&&(i%1000000 == 0)) logger.debug(`writing ${name} phase1: ${i}/${plonkConstraints.length}`);
}
for (let s=0; s<plonkNVars; s++) {
if (typeof firstPos[s] !== "undefined") {
sigma.set(lastAparence[s], firstPos[s]*n8r);
} else {
throw new Error("Variable not used");
}
if ((logger)&&(s%1000000 == 0)) logger.debug(`writing ${name} phase2: ${s}/${plonkNVars}`);
}
await startWriteSection(fdZKey, sectionNum);
let S1 = sigma.slice(0, domainSize*n8r);
await writeP4(S1);
let S2 = sigma.slice(domainSize*n8r, domainSize*n8r*2);
await writeP4(S2);
let S3 = sigma.slice(domainSize*n8r*2, domainSize*n8r*3);
await writeP4(S3);
await endWriteSection(fdZKey);
S1 = await Fr.batchFromMontgomery(S1);
S2 = await Fr.batchFromMontgomery(S2);
S3 = await Fr.batchFromMontgomery(S3);
vk.S1= await curve.G1.multiExpAffine(LPoints, S1, logger, "multiexp S1");
vk.S2= await curve.G1.multiExpAffine(LPoints, S2, logger, "multiexp S2");
vk.S3= await curve.G1.multiExpAffine(LPoints, S3, logger, "multiexp S3");
function buildSigma(s, p) {
if (typeof lastAparence[s] === "undefined") {
firstPos[s] = p;
} else {
sigma.set(lastAparence[s], p*n8r);
}
let v;
if (p<domainSize) {
v = w;
} else if (p<2*domainSize) {
v = Fr.mul(w, k1);
} else {
v = Fr.mul(w, k2);
}
lastAparence[s]=v;
}
}
async function writeLs(sectionNum, name) {
await startWriteSection(fdZKey, sectionNum);
const l=Math.max(nPublic, 1);
for (let i=0; i<l; i++) {
let buff = new BigBuffer(domainSize*n8r);
buff.set(Fr.one, i*n8r);
await writeP4(buff);
if (logger) logger.debug(`writing ${name} ${i}/${l}`);
}
await endWriteSection(fdZKey);
}
async function writeHeaders() {
// Write the header
///////////
await startWriteSection(fdZKey, 1);
await fdZKey.writeULE32(2); // Plonk
await endWriteSection(fdZKey);
// Write the Plonk header section
///////////
await startWriteSection(fdZKey, 2);
const primeQ = curve.q;
const n8q = (Math.floor( (Scalar.bitLength(primeQ) - 1) / 64) +1)*8;
const primeR = curve.r;
const n8r = (Math.floor( (Scalar.bitLength(primeR) - 1) / 64) +1)*8;
await fdZKey.writeULE32(n8q);
await writeBigInt(fdZKey, primeQ, n8q);
await fdZKey.writeULE32(n8r);
await writeBigInt(fdZKey, primeR, n8r);
await fdZKey.writeULE32(plonkNVars); // Total number of bars
await fdZKey.writeULE32(nPublic); // Total number of public vars (not including ONE)
await fdZKey.writeULE32(domainSize); // domainSize
await fdZKey.writeULE32(plonkAdditions.length); // domainSize
await fdZKey.writeULE32(plonkConstraints.length);
await fdZKey.write(k1);
await fdZKey.write(k2);
await fdZKey.write(G1.toAffine(vk.Qm));
await fdZKey.write(G1.toAffine(vk.Ql));
await fdZKey.write(G1.toAffine(vk.Qr));
await fdZKey.write(G1.toAffine(vk.Qo));
await fdZKey.write(G1.toAffine(vk.Qc));
await fdZKey.write(G1.toAffine(vk.S1));
await fdZKey.write(G1.toAffine(vk.S2));
await fdZKey.write(G1.toAffine(vk.S3));
let bX_2;
bX_2 = await fdPTau.read(sG2, sectionsPTau[3][0].p + sG2);
await fdZKey.write(bX_2);
await endWriteSection(fdZKey);
}
function getK1K2() {
let k1 = Fr.two;
while (isIncluded(k1, [], cirPower)) Fr.add(k1, Fr.one);
let k2 = Fr.add(k1, Fr.one);
while (isIncluded(k2, [k1], cirPower)) Fr.add(k2, Fr.one);
return [k1, k2];
function isIncluded(k, kArr, pow) {
const domainSize= 2**pow;
let w = Fr.one;
for (let i=0; i<domainSize; i++) {
if (Fr.eq(k, w)) return true;
for (let j=0; j<kArr.length; j++) {
if (Fr.eq(k, Fr.mul(kArr[j], w))) return true;
}
w = Fr.mul(w, Fr.w[pow]);
}
return false;
}
}
}

398
src/plonk_verify.js Normal file

@ -0,0 +1,398 @@
/*
Copyright 2021 0kims association.
This file is part of snarkjs.
snarkjs is a free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
snarkjs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
/* Implementation of this paper: https://eprint.iacr.org/2019/953.pdf */
import { Scalar } from "ffjavascript";
import * as curves from "./curves.js";
import { utils } from "ffjavascript";
const {unstringifyBigInts} = utils;
import jsSha3 from "js-sha3";
const { keccak256 } = jsSha3;
export default async function plonkVerify(vk_verifier, publicSignals, proof, logger) {
vk_verifier = unstringifyBigInts(vk_verifier);
proof = unstringifyBigInts(proof);
publicSignals = unstringifyBigInts(publicSignals);
const curve = await curves.getCurveFromName(vk_verifier.curve);
const Fr = curve.Fr;
const G1 = curve.G1;
proof = fromObjectProof(curve,proof);
vk_verifier = fromObjectVk(curve, vk_verifier);
if (!isWellConstructed(curve, proof)) {
logger.error("Proof is not well constructed");
return false;
}
const challanges = calculateChallanges(curve, proof);
if (logger) {
logger.debug("beta: " + Fr.toString(challanges.beta, 16));
logger.debug("gamma: " + Fr.toString(challanges.gamma, 16));
logger.debug("alpha: " + Fr.toString(challanges.alpha, 16));
logger.debug("xi: " + Fr.toString(challanges.xi, 16));
logger.debug("v1: " + Fr.toString(challanges.v[1], 16));
logger.debug("v6: " + Fr.toString(challanges.v[6], 16));
logger.debug("u: " + Fr.toString(challanges.u, 16));
}
const L = calculateLagrangeEvaluations(curve, challanges, vk_verifier);
if (logger) {
logger.debug("Lagrange Evaluations: ");
for (let i=1; i<L.length; i++) {
logger.debug(`L${i}(xi)=` + Fr.toString(L[i], 16));
}
}
if (publicSignals.length != vk_verifier.nPublic) {
logger.error("Number of public signals does not match with vk");
return false;
}
const pl = calculatePl(curve, publicSignals, L);
if (logger) {
logger.debug("Pl: " + Fr.toString(pl, 16));
}
const t = calculateT(curve, proof, challanges, pl, L[1]);
if (logger) {
logger.debug("t: " + Fr.toString(t, 16));
}
const D = calculateD(curve, proof, challanges, vk_verifier, L[1]);
if (logger) {
logger.debug("D: " + G1.toString(G1.toAffine(D), 16));
}
const F = calculateF(curve, proof, challanges, vk_verifier, D);
if (logger) {
logger.debug("F: " + G1.toString(G1.toAffine(F), 16));
}
const E = calculateE(curve, proof, challanges, vk_verifier, t);
if (logger) {
logger.debug("E: " + G1.toString(G1.toAffine(E), 16));
}
const res = await isValidPairing(curve, proof, challanges, vk_verifier, E, F);
if (logger) {
if (res) {
logger.info("OK!");
} else {
logger.warn("Invalid Proof");
}
}
return res;
}
function fromObjectProof(curve, proof) {
const G1 = curve.G1;
const Fr = curve.Fr;
const res = {};
res.A = G1.fromObject(proof.A);
res.B = G1.fromObject(proof.B);
res.C = G1.fromObject(proof.C);
res.Z = G1.fromObject(proof.Z);
res.T1 = G1.fromObject(proof.T1);
res.T2 = G1.fromObject(proof.T2);
res.T3 = G1.fromObject(proof.T3);
res.eval_a = Fr.fromObject(proof.eval_a);
res.eval_b = Fr.fromObject(proof.eval_b);
res.eval_c = Fr.fromObject(proof.eval_c);
res.eval_zw = Fr.fromObject(proof.eval_zw);
res.eval_s1 = Fr.fromObject(proof.eval_s1);
res.eval_s2 = Fr.fromObject(proof.eval_s2);
res.eval_r = Fr.fromObject(proof.eval_r);
res.Wxi = G1.fromObject(proof.Wxi);
res.Wxiw = G1.fromObject(proof.Wxiw);
return res;
}
function fromObjectVk(curve, vk) {
const G1 = curve.G1;
const G2 = curve.G2;
const Fr = curve.Fr;
const res = vk;
res.Qm = G1.fromObject(vk.Qm);
res.Ql = G1.fromObject(vk.Ql);
res.Qr = G1.fromObject(vk.Qr);
res.Qo = G1.fromObject(vk.Qo);
res.Qc = G1.fromObject(vk.Qc);
res.S1 = G1.fromObject(vk.S1);
res.S2 = G1.fromObject(vk.S2);
res.S3 = G1.fromObject(vk.S3);
res.k1 = Fr.fromObject(vk.k1);
res.k2 = Fr.fromObject(vk.k2);
res.X_2 = G2.fromObject(vk.X_2);
return res;
}
function isWellConstructed(curve, proof) {
const G1 = curve.G1;
if (!G1.isValid(proof.A)) return false;
if (!G1.isValid(proof.B)) return false;
if (!G1.isValid(proof.C)) return false;
if (!G1.isValid(proof.Z)) return false;
if (!G1.isValid(proof.T1)) return false;
if (!G1.isValid(proof.T2)) return false;
if (!G1.isValid(proof.T3)) return false;
if (!G1.isValid(proof.Wxi)) return false;
if (!G1.isValid(proof.Wxiw)) return false;
return true;
}
function calculateChallanges(curve, proof) {
const G1 = curve.G1;
const Fr = curve.Fr;
const n8r = curve.Fr.n8;
const res = {};
const transcript1 = new Uint8Array(G1.F.n8*2*3);
G1.toRprUncompressed(transcript1, 0, proof.A);
G1.toRprUncompressed(transcript1, G1.F.n8*2, proof.B);
G1.toRprUncompressed(transcript1, G1.F.n8*4, proof.C);
res.beta = hashToFr(curve, transcript1);
const transcript2 = new Uint8Array(n8r);
Fr.toRprBE(transcript2, 0, res.beta);
res.gamma = hashToFr(curve, transcript2);
const transcript3 = new Uint8Array(G1.F.n8*2);
G1.toRprUncompressed(transcript3, 0, proof.Z);
res.alpha = hashToFr(curve, transcript3);
const transcript4 = new Uint8Array(G1.F.n8*2*3);
G1.toRprUncompressed(transcript4, 0, proof.T1);
G1.toRprUncompressed(transcript4, G1.F.n8*2, proof.T2);
G1.toRprUncompressed(transcript4, G1.F.n8*4, proof.T3);
res.xi = hashToFr(curve, transcript4);
const transcript5 = new Uint8Array(n8r*7);
Fr.toRprBE(transcript5, 0, proof.eval_a);
Fr.toRprBE(transcript5, n8r, proof.eval_b);
Fr.toRprBE(transcript5, n8r*2, proof.eval_c);
Fr.toRprBE(transcript5, n8r*3, proof.eval_s1);
Fr.toRprBE(transcript5, n8r*4, proof.eval_s2);
Fr.toRprBE(transcript5, n8r*5, proof.eval_zw);
Fr.toRprBE(transcript5, n8r*6, proof.eval_r);
res.v = [];
res.v[1] = hashToFr(curve, transcript5);
for (let i=2; i<=6; i++ ) res.v[i] = Fr.mul(res.v[i-1], res.v[1]);
const transcript6 = new Uint8Array(G1.F.n8*2*2);
G1.toRprUncompressed(transcript6, 0, proof.Wxi);
G1.toRprUncompressed(transcript6, G1.F.n8*2, proof.Wxiw);
res.u = hashToFr(curve, transcript6);
return res;
}
function calculateLagrangeEvaluations(curve, challanges, vk) {
const Fr = curve.Fr;
let xin = challanges.xi;
let domainSize = 1;
for (let i=0; i<vk.power; i++) {
xin = Fr.square(xin);
domainSize *= 2;
}
challanges.xin = xin;
challanges.zh = Fr.sub(xin, Fr.one);
const L = [];
const n = Fr.e(domainSize);
let w = Fr.one;
for (let i=1; i<=Math.max(1, vk.nPublic); i++) {
L[i] = Fr.div(Fr.mul(w, challanges.zh), Fr.mul(n, Fr.sub(challanges.xi, w)));
w = Fr.mul(w, Fr.w[vk.power]);
}
return L;
}
function hashToFr(curve, transcript) {
const v = Scalar.fromRprBE(new Uint8Array(keccak256.arrayBuffer(transcript)));
return curve.Fr.e(v);
}
function calculatePl(curve, publicSignals, L) {
const Fr = curve.Fr;
let pl = Fr.zero;
for (let i=0; i<publicSignals.length; i++) {
const w = Fr.e(publicSignals[i]);
pl = Fr.sub(pl, Fr.mul(w, L[i+1]));
}
return pl;
}
function calculateT(curve, proof, challanges, pl, l1) {
const Fr = curve.Fr;
let num = proof.eval_r;
num = Fr.add(num, pl);
let e1 = proof.eval_a;
e1 = Fr.add(e1, Fr.mul(challanges.beta, proof.eval_s1));
e1 = Fr.add(e1, challanges.gamma);
let e2 = proof.eval_b;
e2 = Fr.add(e2, Fr.mul(challanges.beta, proof.eval_s2));
e2 = Fr.add(e2, challanges.gamma);
let e3 = proof.eval_c;
e3 = Fr.add(e3, challanges.gamma);
let e = Fr.mul(Fr.mul(e1, e2), e3);
e = Fr.mul(e, proof.eval_zw);
e = Fr.mul(e, challanges.alpha);
num = Fr.sub(num, e);
num = Fr.sub(num, Fr.mul(l1, Fr.square(challanges.alpha)));
const t = Fr.div(num, challanges.zh);
return t;
}
function calculateD(curve, proof, challanges, vk, l1) {
const G1 = curve.G1;
const Fr = curve.Fr;
let s1 = Fr.mul(Fr.mul(proof.eval_a, proof.eval_b), challanges.v[1]);
let res = G1.timesFr(vk.Qm, s1);
let s2 = Fr.mul(proof.eval_a, challanges.v[1]);
res = G1.add(res, G1.timesFr(vk.Ql, s2));
let s3 = Fr.mul(proof.eval_b, challanges.v[1]);
res = G1.add(res, G1.timesFr(vk.Qr, s3));
let s4 = Fr.mul(proof.eval_c, challanges.v[1]);
res = G1.add(res, G1.timesFr(vk.Qo, s4));
res = G1.add(res, G1.timesFr(vk.Qc, challanges.v[1]));
const betaxi = Fr.mul(challanges.beta, challanges.xi);
let s6a = proof.eval_a;
s6a = Fr.add(s6a, betaxi);
s6a = Fr.add(s6a, challanges.gamma);
let s6b = proof.eval_b;
s6b = Fr.add(s6b, Fr.mul(betaxi, vk.k1));
s6b = Fr.add(s6b, challanges.gamma);
let s6c = proof.eval_c;
s6c = Fr.add(s6c, Fr.mul(betaxi, vk.k2));
s6c = Fr.add(s6c, challanges.gamma);
let s6 = Fr.mul(Fr.mul(s6a, s6b), s6c);
s6 = Fr.mul(s6, Fr.mul(challanges.alpha, challanges.v[1]));
let s6d = Fr.mul(Fr.mul(l1, Fr.square(challanges.alpha)), challanges.v[1]);
s6 = Fr.add(s6, s6d);
s6 = Fr.add(s6, challanges.u);
res = G1.add(res, G1.timesFr(proof.Z, s6));
let s7a = proof.eval_a;
s7a = Fr.add(s7a, Fr.mul(challanges.beta, proof.eval_s1));
s7a = Fr.add(s7a, challanges.gamma);
let s7b = proof.eval_b;
s7b = Fr.add(s7b, Fr.mul(challanges.beta, proof.eval_s2));
s7b = Fr.add(s7b, challanges.gamma);
let s7 = Fr.mul(s7a, s7b);
s7 = Fr.mul(s7, challanges.alpha);
s7 = Fr.mul(s7, challanges.v[1]);
s7 = Fr.mul(s7, challanges.beta);
s7 = Fr.mul(s7, proof.eval_zw);
res = G1.sub(res, G1.timesFr(vk.S3, s7));
return res;
}
function calculateF(curve, proof, challanges, vk, D) {
const G1 = curve.G1;
const Fr = curve.Fr;
let res = proof.T1;
res = G1.add(res, G1.timesFr(proof.T2, challanges.xin));
res = G1.add(res, G1.timesFr(proof.T3, Fr.square(challanges.xin)));
res = G1.add(res, D);
res = G1.add(res, G1.timesFr(proof.A, challanges.v[2]));
res = G1.add(res, G1.timesFr(proof.B, challanges.v[3]));
res = G1.add(res, G1.timesFr(proof.C, challanges.v[4]));
res = G1.add(res, G1.timesFr(vk.S1, challanges.v[5]));
res = G1.add(res, G1.timesFr(vk.S2, challanges.v[6]));
return res;
}
function calculateE(curve, proof, challanges, vk, t) {
const G1 = curve.G1;
const Fr = curve.Fr;
let s = t;
s = Fr.add(s, Fr.mul(challanges.v[1], proof.eval_r));
s = Fr.add(s, Fr.mul(challanges.v[2], proof.eval_a));
s = Fr.add(s, Fr.mul(challanges.v[3], proof.eval_b));
s = Fr.add(s, Fr.mul(challanges.v[4], proof.eval_c));
s = Fr.add(s, Fr.mul(challanges.v[5], proof.eval_s1));
s = Fr.add(s, Fr.mul(challanges.v[6], proof.eval_s2));
s = Fr.add(s, Fr.mul(challanges.u, proof.eval_zw));
const res = G1.timesFr(G1.one, s);
return res;
}
async function isValidPairing(curve, proof, challanges, vk, E, F) {
const G1 = curve.G1;
const Fr = curve.Fr;
let A1 = proof.Wxi;
A1 = G1.add(A1, G1.timesFr(proof.Wxiw, challanges.u));
let B1 = G1.timesFr(proof.Wxi, challanges.xi);
const s = Fr.mul(Fr.mul(challanges.u, challanges.xi), Fr.w[vk.power]);
B1 = G1.add(B1, G1.timesFr(proof.Wxiw, s));
B1 = G1.add(B1, F);
B1 = G1.sub(B1, E);
const res = await curve.pairingEq(
G1.neg(A1) , vk.X_2,
B1 , curve.G2.one
);
return res;
}

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as newAccumulator} from "./powersoftau_new.js";
export {default as exportChallenge} from "./powersoftau_export_challenge.js";

@ -1,10 +1,27 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import Blake2b from "blake2b-wasm";
import * as utils from "./powersoftau_utils.js";
import * as misc from "./misc.js";
import * as binFileUtils from "@iden3/binfileutils";
export default async function beacon(oldPtauFilename, newPTauFilename, name, beaconHashStr,numIterationsExp, logger) {
const beaconHash = misc.hex2ByteArray(beaconHashStr);
if ( (beaconHash.byteLength == 0)

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
// Format of the output
// Hash of the last contribution 64 Bytes
// 2^N*2-1 TauG1 Points (compressed)

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
// Format of the output
// Hash of the last contribution 64 Bytes
// 2^N*2-1 TauG1 Points (uncompressed)

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as utils from "./powersoftau_utils.js";
import * as fastFile from "fastfile";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as utils from "./powersoftau_utils.js";
import * as binFileUtils from "@iden3/binfileutils";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as fastFile from "fastfile";
import Blake2b from "blake2b-wasm";
import * as utils from "./powersoftau_utils.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
/*
Header(1)
n8

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as utils from "./powersoftau_utils.js";
import {BigBuffer} from "ffjavascript";

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as utils from "./powersoftau_utils.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import { Scalar } from "ffjavascript";
import Blake2b from "blake2b-wasm";
import * as keyPair from "./keypair.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import Blake2b from "blake2b-wasm";
import * as utils from "./powersoftau_utils.js";
import * as keyPair from "./keypair.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as print} from "./r1cs_print.js";
export {default as info} from "./r1cs_info.js";
export {default as exportJson} from "./r1cs_export_json.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import {readR1cs} from "r1csfile";
export function stringifyBigInts(Fr, o) {

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import { Scalar } from "ffjavascript";
import { readR1cs } from "r1csfile";

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export default function r1csPrint(r1cs, syms, logger) {
for (let i=0; i<r1cs.constraints.length; i++) {

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as genGroth16Verifier} from "./solidity_gengroth16verifier.js";
export {default as prove} from "./groth16_prove.js";
export {default as validate} from "./groth16_verify.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
const inBrowser = (typeof window !== "undefined");
let NodeWorker;
if (!inBrowser) {

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as calculate} from "./wtns_calculate.js";
export {default as debug} from "./wtns_debug.js";
export {default as exportJson} from "./wtns_export_json.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as fastFile from "fastfile";
import { WitnessCalculatorBuilder } from "circom_runtime";
import * as wtnsUtils from "./wtns_utils.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as fastFile from "fastfile";
import { WitnessCalculatorBuilder } from "circom_runtime";
import * as wtnsUtils from "./wtns_utils.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import {read} from "./wtns_utils.js";
export default async function wtnsExportJson(wtnsFileName) {

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import { Scalar } from "ffjavascript";
import * as binFileUtils from "@iden3/binfileutils";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
export {default as newZKey} from "./zkey_new.js";
export {default as exportBellman} from "./zkey_export_bellman.js";
export {default as importBellman} from "./zkey_import_bellman.js";

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as zkeyUtils from "./zkey_utils.js";
import { getCurveFromQ as getCurve } from "./curves.js";
@ -31,7 +50,12 @@ export default async function beacon(zkeyNameOld, zkeyNameNew, name, beaconHashS
const {fd: fdOld, sections: sections} = await binFileUtils.readBinFile(zkeyNameOld, "zkey", 2);
const zkey = await zkeyUtils.readHeader(fdOld, sections, "groth16");
const zkey = await zkeyUtils.readHeader(fdOld, sections);
if (zkey.protocol != "groth16") {
throw new Error("zkey file is not groth16");
}
const curve = await getCurve(zkey.q);

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
// Format of the output
// Hash of the last contribution 64 Bytes
// 2^N*2-1 TauG1 Points (compressed)

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as zkeyUtils from "./zkey_utils.js";
@ -12,7 +30,10 @@ export default async function phase2contribute(zkeyNameOld, zkeyNameNew, name, e
await Blake2b.ready();
const {fd: fdOld, sections: sections} = await binFileUtils.readBinFile(zkeyNameOld, "zkey", 2);
const zkey = await zkeyUtils.readHeader(fdOld, sections, "groth16");
const zkey = await zkeyUtils.readHeader(fdOld, sections);
if (zkey.protocol != "groth16") {
throw new Error("zkey file is not groth16");
}
const curve = await getCurve(zkey.q);

@ -7,7 +7,10 @@ import { getCurveFromQ as getCurve } from "./curves.js";
export default async function phase2exportMPCParams(zkeyName, mpcparamsName, logger) {
const {fd: fdZKey, sections: sectionsZKey} = await binFileUtils.readBinFile(zkeyName, "zkey", 2);
const zkey = await zkeyUtils.readHeader(fdZKey, sectionsZKey, "groth16");
const zkey = await zkeyUtils.readHeader(fdZKey, sectionsZKey);
if (zkey.protocol != "groth16") {
throw new Error("zkey file is not groth16");
}
const curve = await getCurve(zkey.q);
const sG1 = curve.G1.F.n8*2;
@ -133,4 +136,4 @@ export default async function phase2exportMPCParams(zkeyName, mpcparamsName, log
};
}

@ -1,6 +1,6 @@
import { readZKey as readZKey } from "./zkey_utils.js";
export default async function zkeyExportJson(zkeyFileName, verbose) {
export default async function zkeyExportJson(zkeyFileName) {
const zKey = await readZKey(zkeyFileName, true);

@ -1,4 +1,5 @@
import * as fastFile from "fastfile";
import ejs from "ejs";
import exportVerificationKey from "./zkey_export_verificationkey.js";
// Not ready yet
@ -6,47 +7,11 @@ import exportVerificationKey from "./zkey_export_verificationkey.js";
export default async function exportSolidityVerifier(zKeyName, templateName, logger) {
export default async function exportSolidityVerifier(zKeyName, templates, logger) {
const verificationKey = await exportVerificationKey(zKeyName, logger);
const fd = await fastFile.readExisting(templateName);
const buff = await fd.read(fd.totalSize);
let template = new TextDecoder("utf-8").decode(buff);
let template = templates[verificationKey.protocol];
const vkalpha1_str = `${verificationKey.vk_alpha_1[0].toString()},`+
`${verificationKey.vk_alpha_1[1].toString()}`;
template = template.replace("<%vk_alpha1%>", vkalpha1_str);
const vkbeta2_str = `[${verificationKey.vk_beta_2[0][1].toString()},`+
`${verificationKey.vk_beta_2[0][0].toString()}], `+
`[${verificationKey.vk_beta_2[1][1].toString()},` +
`${verificationKey.vk_beta_2[1][0].toString()}]`;
template = template.replace("<%vk_beta2%>", vkbeta2_str);
const vkgamma2_str = `[${verificationKey.vk_gamma_2[0][1].toString()},`+
`${verificationKey.vk_gamma_2[0][0].toString()}], `+
`[${verificationKey.vk_gamma_2[1][1].toString()},` +
`${verificationKey.vk_gamma_2[1][0].toString()}]`;
template = template.replace("<%vk_gamma2%>", vkgamma2_str);
const vkdelta2_str = `[${verificationKey.vk_delta_2[0][1].toString()},`+
`${verificationKey.vk_delta_2[0][0].toString()}], `+
`[${verificationKey.vk_delta_2[1][1].toString()},` +
`${verificationKey.vk_delta_2[1][0].toString()}]`;
template = template.replace("<%vk_delta2%>", vkdelta2_str);
// The points
template = template.replace("<%vk_input_length%>", (verificationKey.IC.length-1).toString());
template = template.replace("<%vk_ic_length%>", verificationKey.IC.length.toString());
let vi = "";
for (let i=0; i<verificationKey.IC.length; i++) {
if (vi != "") vi = vi + " ";
vi = vi + `vk.IC[${i}] = Pairing.G1Point(${verificationKey.IC[i][0].toString()},`+
`${verificationKey.IC[i][1].toString()});\n`;
}
template = template.replace("<%vk_ic_pts%>", vi);
return template;
return ejs.render(template , verificationKey);
}

@ -1,15 +1,49 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as zkeyUtils from "./zkey_utils.js";
import { getCurveFromQ as getCurve } from "./curves.js";
import { utils } from "ffjavascript";
const {stringifyBigInts} = utils;
export default async function zkeyExportVerificationKey(zkeyName, logger) {
export default async function zkeyExportVerificationKey(zkeyName, /* logger */ ) {
const {fd, sections} = await binFileUtils.readBinFile(zkeyName, "zkey", 2);
const zkey = await zkeyUtils.readHeader(fd, sections, "groth16");
const zkey = await zkeyUtils.readHeader(fd, sections);
let res;
if (zkey.protocol == "groth16") {
res = await groth16Vk(zkey, fd, sections);
} else if (zkey.protocol == "plonk") {
res = await plonkVk(zkey);
} else {
throw new Error("zkey file is not groth16");
}
await fd.close();
return res;
}
async function groth16Vk(zkey, fd, sections) {
const curve = await getCurve(zkey.q);
const sG1 = curve.G1.F.n8*2;
@ -42,7 +76,35 @@ export default async function zkeyExportVerificationKey(zkeyName, logger) {
vKey = stringifyBigInts(vKey);
await fd.close();
return vKey;
}
async function plonkVk(zkey) {
const curve = await getCurve(zkey.q);
let vKey = {
protocol: zkey.protocol,
curve: curve.name,
nPublic: zkey.nPublic,
power: zkey.power,
k1: curve.Fr.toObject(zkey.k1),
k2: curve.Fr.toObject(zkey.k2),
Qm: curve.G1.toObject(zkey.Qm),
Ql: curve.G1.toObject(zkey.Ql),
Qr: curve.G1.toObject(zkey.Qr),
Qo: curve.G1.toObject(zkey.Qo),
Qc: curve.G1.toObject(zkey.Qc),
S1: curve.G1.toObject(zkey.S1),
S2: curve.G1.toObject(zkey.S2),
S3: curve.G1.toObject(zkey.S3),
X_2: curve.G2.toObject(zkey.X_2)
};
vKey = stringifyBigInts(vKey);
return vKey;
}

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as zkeyUtils from "./zkey_utils.js";
import * as binFileUtils from "@iden3/binfileutils";
import * as fastFile from "fastfile";
@ -7,7 +26,10 @@ import * as misc from "./misc.js";
export default async function phase2importMPCParams(zkeyNameOld, mpcparamsName, zkeyNameNew, name, logger) {
const {fd: fdZKeyOld, sections: sectionsZKeyOld} = await binFileUtils.readBinFile(zkeyNameOld, "zkey", 2);
const zkeyHeader = await zkeyUtils.readHeader(fdZKeyOld, sectionsZKeyOld, "groth16");
const zkeyHeader = await zkeyUtils.readHeader(fdZKeyOld, sectionsZKeyOld, false);
if (zkeyHeader.protocol != "groth16") {
throw new Error("zkey file is not groth16");
}
const curve = await getCurve(zkeyHeader.q);
const sG1 = curve.G1.F.n8*2;

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import {readR1csHeader} from "r1csfile";
import * as utils from "./powersoftau_utils.js";

@ -1,3 +1,21 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
// Format
// ======
@ -185,20 +203,30 @@ async function readG2(fd, curve, toObject) {
}
export async function readHeader(fd, sections, protocol, toObject) {
if (protocol != "groth16") throw new Error("Protocol not supported: "+protocol);
const zkey = {};
export async function readHeader(fd, sections, toObject) {
// Read Header
/////////////////////
await binFileUtils.startReadUniqueSection(fd, sections, 1);
const protocolId = await fd.readULE32();
if (protocolId != 1) throw new Error("File is not groth");
zkey.protocol = "groth16";
await binFileUtils.endReadSection(fd);
if (protocolId == 1) {
return await readHeaderGroth16(fd, sections, toObject);
} else if (protocolId == 2) {
return await readHeaderPlonk(fd, sections, toObject);
} else {
throw new Error("Protocol not supported: ");
}
}
async function readHeaderGroth16(fd, sections, toObject) {
const zkey = {};
zkey.protocol = "groth16";
// Read Groth Header
/////////////////////
await binFileUtils.startReadUniqueSection(fd, sections, 2);
@ -228,6 +256,51 @@ export async function readHeader(fd, sections, protocol, toObject) {
}
async function readHeaderPlonk(fd, sections, protocol, toObject) {
const zkey = {};
zkey.protocol = "plonk";
// Read Plonk Header
/////////////////////
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);
let curve = await getCurve(zkey.q);
zkey.nVars = await fd.readULE32();
zkey.nPublic = await fd.readULE32();
zkey.domainSize = await fd.readULE32();
zkey.power = log2(zkey.domainSize);
zkey.nAdditions = await fd.readULE32();
zkey.nConstrains = await fd.readULE32();
zkey.k1 = await fd.read(n8r);
zkey.k2 = await fd.read(n8r);
zkey.Qm = await readG1(fd, curve, toObject);
zkey.Ql = await readG1(fd, curve, toObject);
zkey.Qr = await readG1(fd, curve, toObject);
zkey.Qo = await readG1(fd, curve, toObject);
zkey.Qc = await readG1(fd, curve, toObject);
zkey.S1 = await readG1(fd, curve, toObject);
zkey.S2 = await readG1(fd, curve, toObject);
zkey.S3 = await readG1(fd, curve, toObject);
zkey.X_2 = await readG2(fd, curve, toObject);
await binFileUtils.endReadSection(fd);
return zkey;
}
export async function readZKey(fileName, toObject) {
const {fd, sections} = await binFileUtils.readBinFile(fileName, "zkey", 1);
@ -330,7 +403,7 @@ export async function readZKey(fileName, toObject) {
return zkey;
async function readFr2(toObject) {
async function readFr2(/* toObject */) {
const n = await binFileUtils.readBigInt(fd, zkey.n8r);
return Fr.mul(n, Rri2);
}

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import * as binFileUtils from "@iden3/binfileutils";
import * as zkeyUtils from "./zkey_utils.js";
import { getCurveFromQ as getCurve } from "./curves.js";
@ -6,7 +25,6 @@ import * as misc from "./misc.js";
import { hashToG2 as hashToG2 } from "./keypair.js";
const sameRatio = misc.sameRatio;
import crypto from "crypto";
import newZKey from "./zkey_new.js";
import {hashG1, hashPubKey} from "./zkey_utils.js";
import { Scalar, ChaCha, BigBuffer } from "ffjavascript";
@ -18,11 +36,13 @@ export default async function phase2verifyFromInit(initFileName, pTauFileName, z
await Blake2b.ready();
const {fd, sections} = await binFileUtils.readBinFile(zkeyFileName, "zkey", 2);
const zkey = await zkeyUtils.readHeader(fd, sections, "groth16");
const zkey = await zkeyUtils.readHeader(fd, sections, false);
if (zkey.protocol != "groth16") {
throw new Error("zkey file is not groth16");
}
const curve = await getCurve(zkey.q);
const sG1 = curve.G1.F.n8*2;
const sG2 = curve.G2.F.n8*2;
const mpcParams = await zkeyUtils.readMPCParams(fd, curve, sections);
@ -82,7 +102,11 @@ export default async function phase2verifyFromInit(initFileName, pTauFileName, z
const {fd: fdInit, sections: sectionsInit} = await binFileUtils.readBinFile(initFileName, "zkey", 2);
const zkeyInit = await zkeyUtils.readHeader(fdInit, sectionsInit, "groth16");
const zkeyInit = await zkeyUtils.readHeader(fdInit, sectionsInit, false);
if (zkeyInit.protocol != "groth16") {
throw new Error("zkeyinit file is not groth16");
}
if ( (!Scalar.eq(zkeyInit.q, zkey.q))
||(!Scalar.eq(zkeyInit.r, zkey.r))

@ -1,3 +1,22 @@
/*
Copyright 2018 0KIMS association.
This file is part of snarkJS.
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
import newZKey from "./zkey_new.js";
import phase2verifyFromInit from "./zkey_verify_frominit.js";

@ -176,12 +176,36 @@ contract Verifier {
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(<%vk_alpha1%>);
vk.beta2 = Pairing.G2Point(<%vk_beta2%>);
vk.gamma2 = Pairing.G2Point(<%vk_gamma2%>);
vk.delta2 = Pairing.G2Point(<%vk_delta2%>);
vk.IC = new Pairing.G1Point[](<%vk_ic_length%>);
<%vk_ic_pts%>
vk.alfa1 = Pairing.G1Point(
<%=vk_alpha_1[0]%>,
<%=vk_alpha_1[1]%>
);
vk.beta2 = Pairing.G2Point(
[<%=vk_beta_2[0][1]%>,
<%=vk_beta_2[0][0]%>],
[<%=vk_beta_2[1][1]%>,
<%=vk_beta_2[1][0]%>]
);
vk.gamma2 = Pairing.G2Point(
[<%=vk_gamma_2[0][1]%>,
<%=vk_gamma_2[0][0]%>],
[<%=vk_gamma_2[1][1]%>,
<%=vk_gamma_2[1][0]%>]
);
vk.delta2 = Pairing.G2Point(
[<%=vk_delta_2[0][1]%>,
<%=vk_delta_2[0][0]%>],
[<%=vk_delta_2[1][1]%>,
<%=vk_delta_2[1][0]%>]
);
vk.IC = new Pairing.G1Point[](<%=IC.length%>);
<% for (let i=0; i<IC.length; i++) { %>
vk.IC[<%=i%>] = Pairing.G1Point(
<%=IC[i][0]%>,
<%=IC[i][1]%>
);
<% } %>
}
function verify(uint[] memory input, Proof memory proof) internal view returns (uint) {
uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
@ -207,7 +231,7 @@ contract Verifier {
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[<%vk_input_length%>] memory input
uint[<%=IC.length-1%>] memory input
) public view returns (bool r) {
Proof memory proof;
proof.A = Pairing.G1Point(a[0], a[1]);

@ -0,0 +1,632 @@
// SPDX-License-Identifier: GPL-3.0
/*
Copyright 2021 0KIMS association.
This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.7.0 <0.9.0;
contract PlonkVerifier {
uint16 constant n = <%=2**power%>;
uint16 constant nPublic = <%=nPublic%>;
uint16 constant nLagrange = <%=Math.max(nPublic, 1)%>;
uint256 constant Qmx = <%=Qm[0]%>;
uint256 constant Qmy = <%=Qm[1]%>;
uint256 constant Qlx = <%=Ql[0]%>;
uint256 constant Qly = <%=Ql[1]%>;
uint256 constant Qrx = <%=Qr[0]%>;
uint256 constant Qry = <%=Qr[1]%>;
uint256 constant Qox = <%=Qo[0]%>;
uint256 constant Qoy = <%=Qo[1]%>;
uint256 constant Qcx = <%=Qc[0]%>;
uint256 constant Qcy = <%=Qc[1]%>;
uint256 constant S1x = <%=S1[0]%>;
uint256 constant S1y = <%=S1[1]%>;
uint256 constant S2x = <%=S2[0]%>;
uint256 constant S2y = <%=S2[1]%>;
uint256 constant S3x = <%=S3[0]%>;
uint256 constant S3y = <%=S3[1]%>;
uint256 constant k1 = 2;
uint256 constant k2 = 3;
uint256 constant X2x1 = <%=X_2[0][0]%>;
uint256 constant X2x2 = <%=X_2[0][1]%>;
uint256 constant X2y1 = <%=X_2[1][0]%>;
uint256 constant X2y2 = <%=X_2[1][1]%>;
uint256 constant q = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 constant qf = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
uint256 constant w1 = 19540430494807482326159819597004422086093766032135589407132600596362845576832;
uint256 constant G1x = 1;
uint256 constant G1y = 2;
uint256 constant G2x1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant G2x2 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 constant G2y1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant G2y2 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint16 constant pA = 32;
uint16 constant pB = 96;
uint16 constant pC = 160;
uint16 constant pZ = 224;
uint16 constant pT1 = 288;
uint16 constant pT2 = 352;
uint16 constant pT3 = 416;
uint16 constant pWxi = 480;
uint16 constant pWxiw = 544;
uint16 constant pEval_a = 608;
uint16 constant pEval_b = 640;
uint16 constant pEval_c = 672;
uint16 constant pEval_s1 = 704;
uint16 constant pEval_s2 = 736;
uint16 constant pEval_zw = 768;
uint16 constant pEval_r = 800;
uint16 constant pAlpha = 0;
uint16 constant pBeta = 32;
uint16 constant pGamma = 64;
uint16 constant pXi = 96;
uint16 constant pXin = 128;
uint16 constant pBetaXi = 160;
uint16 constant pV1 = 192;
uint16 constant pV2 = 224;
uint16 constant pV3 = 256;
uint16 constant pV4 = 288;
uint16 constant pV5 = 320;
uint16 constant pV6 = 352;
uint16 constant pU = 384;
uint16 constant pPl = 416;
uint16 constant pEval_t = 448;
uint16 constant pA1 = 480;
uint16 constant pB1 = 544;
uint16 constant pZh = 608;
uint16 constant pZhInv = 640;
<% for (let i=1; i<=Math.max(nPublic, 1); i++) { %>
uint16 constant pEval_l<%=i%> = <%=640+i*32%>;
<% } %>
uint16 constant lastMem = <%=672+32*Math.max(nPublic,1)%>;
function verifyProof(bytes memory proof, uint[] memory pubSignals) public view returns (bool) {
assembly {
/////////
// Computes the inverse using the extended euclidean algorithm
/////////
function inverse(a, q) -> inv {
let t := 0
let newt := 1
let r := q
let newr := a
let quotient
let aux
for { } newr { } {
quotient := sdiv(r, newr)
aux := sub(t, mul(quotient, newt))
t:= newt
newt:= aux
aux := sub(r,mul(quotient, newr))
r := newr
newr := aux
}
if gt(r, 1) { revert(0,0) }
if slt(t, 0) { t:= add(t, q) }
inv := t
}
///////
// Computes the inverse of an array of values
// See https://vitalik.ca/general/2018/07/21/starks_part_3.html in section where explain fields operations
//////
function inverseArray(pVals, n) {
let pAux := mload(0x40) // Point to the next free position
let pIn := pVals
let lastPIn := add(pVals, mul(n, 32)) // Read n elemnts
let acc := mload(pIn) // Read the first element
pIn := add(pIn, 32) // Point to the second element
let inv
for { } lt(pIn, lastPIn) {
pAux := add(pAux, 32)
pIn := add(pIn, 32)
}
{
mstore(pAux, acc)
acc := mulmod(acc, mload(pIn), q)
}
acc := inverse(acc, q)
// At this point pAux pint to the next free position we substract 1 to point to the last used
pAux := sub(pAux, 32)
// pIn points to the n+1 element, we substract to point to n
pIn := sub(pIn, 32)
lastPIn := pVals // We don't process the first element
for { } gt(pIn, lastPIn) {
pAux := sub(pAux, 32)
pIn := sub(pIn, 32)
}
{
inv := mulmod(acc, mload(pAux), q)
acc := mulmod(acc, mload(pIn), q)
mstore(pIn, inv)
}
// pIn points to first element, we just set it.
mstore(pIn, acc)
}
function checkField(v) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0,0x20)
}
}
function checkInput(pProof) {
if iszero(eq(mload(pProof), 800 )) {
mstore(0, 0)
return(0,0x20)
}
checkField(mload(add(pProof, pEval_a)))
checkField(mload(add(pProof, pEval_b)))
checkField(mload(add(pProof, pEval_c)))
checkField(mload(add(pProof, pEval_s1)))
checkField(mload(add(pProof, pEval_s2)))
checkField(mload(add(pProof, pEval_zw)))
checkField(mload(add(pProof, pEval_r)))
// Points are checked in the point operations precompiled smart contracts
}
function calculateChallanges(pProof, pMem) {
let a
let b
b := mod(keccak256(add(pProof, pA), 192), q)
mstore( add(pMem, pBeta), b)
mstore( add(pMem, pGamma), mod(keccak256(add(pMem, pBeta), 32), q))
mstore( add(pMem, pAlpha), mod(keccak256(add(pProof, pZ), 64), q))
a := mod(keccak256(add(pProof, pT1), 192), q)
mstore( add(pMem, pXi), a)
mstore( add(pMem, pBetaXi), mulmod(b, a, q))
<%for (let i=0; i<power;i++) {%>
a:= mulmod(a, a, q)
<%}%>
mstore( add(pMem, pXin), a)
a:= mod(add(sub(a, 1),q), q)
mstore( add(pMem, pZh), a)
mstore( add(pMem, pZhInv), a) // We will invert later together with lagrange pols
let v1 := mod(keccak256(add(pProof, pEval_a), 224), q)
mstore( add(pMem, pV1), v1)
a := mulmod(v1, v1, q)
mstore( add(pMem, pV2), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV3), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV4), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV5), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV6), a)
mstore( add(pMem, pU), mod(keccak256(add(pProof, pWxi), 128), q))
}
function calculateLagrange(pMem) {
let w := 1
<% for (let i=1; i<=Math.max(nPublic, 1); i++) { %>
mstore(
add(pMem, pEval_l<%=i%>),
mulmod(
n,
mod(
add(
sub(
mload(add(pMem, pXi)),
w
),
q
),
q
),
q
)
)
<% if (i<Math.max(nPublic, 1)) { %>
w := mulmod(w, w1, q)
<% } %>
<% } %>
inverseArray(add(pMem, pZhInv), <%=Math.max(nPublic, 1)+1%> )
let zh := mload(add(pMem, pZh))
w := 1
<% for (let i=1; i<=Math.max(nPublic, 1); i++) { %>
<% if (i==1) { %>
mstore(
add(pMem, pEval_l1 ),
mulmod(
mload(add(pMem, pEval_l1 )),
zh,
q
)
)
<% } else { %>
mstore(
add(pMem, pEval_l<%=i%>),
mulmod(
w,
mulmod(
mload(add(pMem, pEval_l<%=i%>)),
zh,
q
),
q
)
)
<% } %>
<% if (i<Math.max(nPublic, 1)) { %>
w := mulmod(w, w1, q)
<% } %>
<% } %>
}
function calculatePl(pMem, pPub) {
let pl := 0
<% for (let i=0; i<nPublic; i++) { %>
pl := mod(
add(
sub(
pl,
mulmod(
mload(add(pMem, pEval_l<%=i+1%>)),
mload(add(pPub, <%=32+i*32%>)),
q
)
),
q
),
q
)
<% } %>
mstore(add(pMem, pPl), pl)
}
function calculateT(pProof, pMem) {
let t
let t1
let t2
t := addmod(
mload(add(pProof, pEval_r)),
mload(add(pMem, pPl)),
q
)
t1 := mulmod(
mload(add(pProof, pEval_s1)),
mload(add(pMem, pBeta)),
q
)
t1 := addmod(
t1,
mload(add(pProof, pEval_a)),
q
)
t1 := addmod(
t1,
mload(add(pMem, pGamma)),
q
)
t2 := mulmod(
mload(add(pProof, pEval_s2)),
mload(add(pMem, pBeta)),
q
)
t2 := addmod(
t2,
mload(add(pProof, pEval_b)),
q
)
t2 := addmod(
t2,
mload(add(pMem, pGamma)),
q
)
t1 := mulmod(t1, t2, q)
t2 := addmod(
mload(add(pProof, pEval_c)),
mload(add(pMem, pGamma)),
q
)
t1 := mulmod(t1, t2, q)
t1 := mulmod(t1, mload(add(pProof, pEval_zw)), q)
t1 := mulmod(t1, mload(add(pMem, pAlpha)), q)
t2 := mulmod(
mload(add(pMem, pEval_l1)),
mload(add(pMem, pAlpha)),
q
)
t2 := mulmod(
t2,
mload(add(pMem, pAlpha)),
q
)
t1 := addmod(t1, t2, q)
t := mod(sub(add(t, q), t1), q)
t := mulmod(t, mload(add(pMem, pZhInv)), q)
mstore( add(pMem, pEval_t) , t)
}
function g1_set(pR, pP) {
mstore(pR, mload(pP))
mstore(add(pR, 32), mload(add(pP,32)))
}
function g1_acc(pR, pP) {
let mIn := mload(0x40)
mstore(mIn, mload(pR))
mstore(add(mIn,32), mload(add(pR, 32)))
mstore(add(mIn,64), mload(pP))
mstore(add(mIn,96), mload(add(pP, 32)))
let success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function g1_mulAcc(pR, pP, s) {
let success
let mIn := mload(0x40)
mstore(mIn, mload(pP))
mstore(add(mIn,32), mload(add(pP, 32)))
mstore(add(mIn,64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
mstore(add(mIn,64), mload(pR))
mstore(add(mIn,96), mload(add(pR, 32)))
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function g1_mulAccC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn,32), y)
mstore(add(mIn,64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
mstore(add(mIn,64), mload(pR))
mstore(add(mIn,96), mload(add(pR, 32)))
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function g1_mulSetC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn,32), y)
mstore(add(mIn,64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function calculateA1(pProof, pMem) {
let p := add(pMem, pA1)
g1_set(p, add(pProof, pWxi))
g1_mulAcc(p, add(pProof, pWxiw), mload(add(pMem, pU)))
}
function calculateB1(pProof, pMem) {
let s
let s1
let p := add(pMem, pB1)
// Calculate D
s := mulmod( mload(add(pProof, pEval_a)), mload(add(pMem, pV1)), q)
g1_mulSetC(p, Qlx, Qly, s)
s := mulmod( s, mload(add(pProof, pEval_b)), q)
g1_mulAccC(p, Qmx, Qmy, s)
s := mulmod( mload(add(pProof, pEval_b)), mload(add(pMem, pV1)), q)
g1_mulAccC(p, Qrx, Qry, s)
s := mulmod( mload(add(pProof, pEval_c)), mload(add(pMem, pV1)), q)
g1_mulAccC(p, Qox, Qoy, s)
s :=mload(add(pMem, pV1))
g1_mulAccC(p, Qcx, Qcy, s)
s := addmod(mload(add(pProof, pEval_a)), mload(add(pMem, pBetaXi)), q)
s := addmod(s, mload(add(pMem, pGamma)), q)
s1 := mulmod(k1, mload(add(pMem, pBetaXi)), q)
s1 := addmod(s1, mload(add(pProof, pEval_b)), q)
s1 := addmod(s1, mload(add(pMem, pGamma)), q)
s := mulmod(s, s1, q)
s1 := mulmod(k2, mload(add(pMem, pBetaXi)), q)
s1 := addmod(s1, mload(add(pProof, pEval_c)), q)
s1 := addmod(s1, mload(add(pMem, pGamma)), q)
s := mulmod(s, s1, q)
s := mulmod(s, mload(add(pMem, pAlpha)), q)
s := mulmod(s, mload(add(pMem, pV1)), q)
s1 := mulmod(mload(add(pMem, pEval_l1)), mload(add(pMem, pAlpha)), q)
s1 := mulmod(s1, mload(add(pMem, pAlpha)), q)
s1 := mulmod(s1, mload(add(pMem, pV1)), q)
s := addmod(s, s1, q)
s := addmod(s, mload(add(pMem, pU)), q)
g1_mulAcc(p, add(pProof, pZ), s)
s := mulmod(mload(add(pMem, pBeta)), mload(add(pProof, pEval_s1)), q)
s := addmod(s, mload(add(pProof, pEval_a)), q)
s := addmod(s, mload(add(pMem, pGamma)), q)
s1 := mulmod(mload(add(pMem, pBeta)), mload(add(pProof, pEval_s2)), q)
s1 := addmod(s1, mload(add(pProof, pEval_b)), q)
s1 := addmod(s1, mload(add(pMem, pGamma)), q)
s := mulmod(s, s1, q)
s := mulmod(s, mload(add(pMem, pAlpha)), q)
s := mulmod(s, mload(add(pMem, pV1)), q)
s := mulmod(s, mload(add(pMem, pBeta)), q)
s := mulmod(s, mload(add(pProof, pEval_zw)), q)
s := mod(sub(q, s), q)
g1_mulAccC(p, S3x, S3y, s)
// calculate F
g1_acc(p , add(pProof, pT1))
s := mload(add(pMem, pXin))
g1_mulAcc(p, add(pProof, pT2), s)
s := mulmod(s, s, q)
g1_mulAcc(p, add(pProof, pT3), s)
g1_mulAcc(p, add(pProof, pA), mload(add(pMem, pV2)))
g1_mulAcc(p, add(pProof, pB), mload(add(pMem, pV3)))
g1_mulAcc(p, add(pProof, pC), mload(add(pMem, pV4)))
g1_mulAccC(p, S1x, S1y, mload(add(pMem, pV5)))
g1_mulAccC(p, S2x, S2y, mload(add(pMem, pV6)))
// calculate E
s := mload(add(pMem, pEval_t))
s := addmod(s, mulmod(mload(add(pProof, pEval_r)), mload(add(pMem, pV1)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_a)), mload(add(pMem, pV2)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_b)), mload(add(pMem, pV3)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_c)), mload(add(pMem, pV4)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_s1)), mload(add(pMem, pV5)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_s2)), mload(add(pMem, pV6)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_zw)), mload(add(pMem, pU)), q), q)
s := mod(sub(q, s), q)
g1_mulAccC(p, G1x, G1y, s)
// Last part of B
s := mload(add(pMem, pXi))
g1_mulAcc(p, add(pProof, pWxi), s)
s := mulmod(mload(add(pMem, pU)), mload(add(pMem, pXi)), q)
s := mulmod(s, w1, q)
g1_mulAcc(p, add(pProof, pWxiw), s)
}
function checkPairing(pMem) -> isOk {
let mIn := mload(0x40)
mstore(mIn, mload(add(pMem, pA1)))
mstore(add(mIn,32), mload(add(add(pMem, pA1), 32)))
mstore(add(mIn,64), X2x2)
mstore(add(mIn,96), X2x1)
mstore(add(mIn,128), X2y2)
mstore(add(mIn,160), X2y1)
mstore(add(mIn,192), mload(add(pMem, pB1)))
let s := mload(add(add(pMem, pB1), 32))
s := mod(sub(qf, s), qf)
mstore(add(mIn,224), s)
mstore(add(mIn,256), G2x2)
mstore(add(mIn,288), G2x1)
mstore(add(mIn,320), G2y2)
mstore(add(mIn,352), G2y1)
let success := staticcall(sub(gas(), 2000), 8, mIn, 384, mIn, 0x20)
isOk := and(success, mload(mIn))
}
let pMem := mload(0x40)
mstore(0x40, add(pMem, lastMem))
checkInput(proof)
calculateChallanges(proof, pMem)
calculateLagrange(pMem)
calculatePl(pMem, pubSignals)
calculateT(proof, pMem)
calculateA1(proof, pMem)
calculateB1(proof, pMem)
let isValid := checkPairing(pMem)
mstore(0x40, sub(pMem, lastMem))
mstore(0, isValid)
return(0,0x20)
}
}
}

Binary file not shown.

Binary file not shown.

@ -18,9 +18,11 @@ describe("Full process", function () {
const zkey_1 = {type: "mem"};
const zkey_2 = {type: "mem"};
const zkey_final = {type: "mem"};
const zkey_plonk = {type: "mem"};
const bellman_1 = {type: "mem"};
const bellman_2 = {type: "mem"};
let vKey;
let vKeyPlonk;
const wtns = {type: "mem"};
let proof;
let publicSignals;
@ -36,7 +38,7 @@ describe("Full process", function () {
});
it ("powersoftau new", async () => {
await snarkjs.powersOfTau.newAccumulator(curve, 10, ptau_0);
await snarkjs.powersOfTau.newAccumulator(curve, 11, ptau_0);
});
it ("powersoftau contribute ", async () => {
@ -68,7 +70,7 @@ describe("Full process", function () {
assert(res);
});
it ("zkey new", async () => {
it ("groth16 setup", async () => {
await snarkjs.zKey.newZKey(path.join("test", "circuit", "circuit.r1cs"), ptau_final, zkey_0);
});
@ -116,9 +118,31 @@ describe("Full process", function () {
publicSignals = res.publicSignals;
});
it ("groth16 verify", async () => {
const res = await snarkjs.groth16.verify(vKey, publicSignals, proof);
assert(res == true);
});
it ("plonk setup", async () => {
await snarkjs.plonk.setup(path.join("test", "circuit", "circuit.r1cs"), ptau_final, zkey_plonk);
});
it ("zkey export verificationkey", async () => {
vKey = await snarkjs.zKey.exportVerificationKey(zkey_plonk);
});
it ("plonk proof", async () => {
const res = await snarkjs.plonk.prove(zkey_plonk, wtns);
proof = res.proof;
publicSignals = res.publicSignals;
});
it ("plonk verify", async () => {
const res = await snarkjs.plonk.verify(vKey, publicSignals, proof);
assert(res == true);
});
});

@ -0,0 +1,17 @@
template TestPlonk() {
signal input a;
signal private input b;
signal output c;
signal i1;
signal i2;
signal i4;
i1 <== a+b+3;
i2 <== i1*i1;
i4 <== i2*i2;
c <== i1*i4;
}
component main = TestPlonk();

Binary file not shown.

@ -0,0 +1,6 @@
1,2,0,main.a
2,3,0,main.b
3,1,0,main.c
4,4,0,main.i1
5,5,0,main.i2
6,6,0,main.i4

Binary file not shown.

Binary file not shown.

@ -0,0 +1 @@
{"a":1, "b":2}

Binary file not shown.

@ -0,0 +1,56 @@
{
"A": [
"11939839401037308014501661426368356653724850605345253332929657172853812043781",
"16803150087255544989431958662488492904420336924238680701501581437584428607157",
"1"
],
"B": [
"12217796857989229870486480566571024020165537615492120027996617913635583550919",
"15953050028732489401139070996642159829273127420498389055201687358737110395633",
"1"
],
"C": [
"2906696582521990272421790638819759482269959041206664482786284127016128717160",
"13202026981472500389768834017524824796942889042108968745956553624097139985303",
"1"
],
"Z": [
"12963117237509670288018978167117384995558675963765854814463910896579884709481",
"4622289012016200197589549612287854254636168290945719641009001753279825228149",
"1"
],
"T1": [
"18104357506804140563327524454292715928794326274573109553633239600891197573562",
"538095434184877169430117038240223945215803059446062355137183333593880141605",
"1"
],
"T2": [
"11026905931134233808041270707862602948406795505689051352903565023828166906250",
"18119786770119651916429915278124137884233023858386753737488502838895847215949",
"1"
],
"T3": [
"17566889279472128646779664131922958011041076031971155851685601770551415716030",
"9098203299195991935285362173962848018633069009185836024035896571651321000209",
"1"
],
"eval_a": "18055865061248928277436374209575542340767389401367587042080949450055475826552",
"eval_b": "21850645998014953033835315242107188012141028920551179313126430204177981301827",
"eval_c": "5824117629917668551774989696896451058359923623432918656361263478103100196767",
"eval_s1": "65743854351722680405937613500622654105481480423395233482389298676037124381",
"eval_s2": "403993049457837292639608362612899661597754187086038035508895737334683813284",
"eval_zw": "14169472644142979719809496569719127849776868311673021350864638375395829014729",
"eval_r": "9395413794097544253619189223051084436435081924218993403215287776407899118006",
"Wxi": [
"3539391490802181190120434708628288229123728841695494613225112420761229267477",
"19988904286663115119238205828592812126968004685055289879546007973679529590700",
"1"
],
"Wxiw": [
"19317464275069150558817973507256614963505445298046435829549010698677013964612",
"16876609931905898917226763969880049506487107879332614688130170393689647229232",
"1"
],
"protocol": "plonk",
"curve": "bn128"
}

@ -0,0 +1,4 @@
[
"7776",
"1"
]

@ -0,0 +1,62 @@
{
"protocol": "plonk",
"curve": "bn128",
"nPublic": 2,
"power": 3,
"k1": "2",
"k2": "3",
"Qm": [
"4574976860925876233715815557145957880705707179788243092345689458042383890488",
"4280641572679440220740870768701934042005081764212788702122100316880968332003",
"1"
],
"Ql": [
"965658296392348546197801330054212493203716810675203464920320569299615906620",
"2656007013467620250344837426700774817845582578535592475523934494973414078961",
"1"
],
"Qr": [
"9466120146806803512081752933000124200435544680867502413168004293837549973279",
"21718061423910769411439185483074527939398926867139106591112998426662463026765",
"1"
],
"Qo": [
"14232475876760437187555678371073865360567175818750566973123447255794615727867",
"12884948380030714721172201264029036846611910042838904312559968631894569296588",
"1"
],
"Qc": [
"14611255151810715369553599153356422265550902840832241273629187752840438096443",
"9099095607583972457036848580058361056377035074964862926640921566382822995435",
"1"
],
"S1": [
"14533465958261944855196820716374074689704505288368818447966063234824080424576",
"12453353674569653145950160230568106433424266373528956571501497772329286407421",
"1"
],
"S2": [
"19581287390493194877650947725652399954855738146667446650367315521331119724530",
"13292535777423157488265774466403939589622049710743071078999542362804505686482",
"1"
],
"S3": [
"7628615832235497959754170049702774596960536866278288444040861507702299255530",
"6061093738111279431632848690609155827426019335581022466737969401920480256170",
"1"
],
"X_2": [
[
"18029695676650738226693292988307914797657423701064905010927197838374790804409",
"14583779054894525174450323658765874724019480979794335525732096752006891875705"
],
[
"2140229616977736810657479771656733941598412651537078903776637920509952744750",
"11474861747383700316476719153975578001603231366361248090558603872215261634898"
],
[
"1",
"0"
]
]
}

@ -0,0 +1,675 @@
// SPDX-License-Identifier: GPL-3.0
/*
Copyright 2021 0KIMS association.
This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.7.0 <0.9.0;
contract PlonkVerifier {
uint16 constant n = 8;
uint16 constant nPublic = 2;
uint16 constant nLagrange = 2;
uint256 constant Qmx = 4574976860925876233715815557145957880705707179788243092345689458042383890488;
uint256 constant Qmy = 4280641572679440220740870768701934042005081764212788702122100316880968332003;
uint256 constant Qlx = 965658296392348546197801330054212493203716810675203464920320569299615906620;
uint256 constant Qly = 2656007013467620250344837426700774817845582578535592475523934494973414078961;
uint256 constant Qrx = 9466120146806803512081752933000124200435544680867502413168004293837549973279;
uint256 constant Qry = 21718061423910769411439185483074527939398926867139106591112998426662463026765;
uint256 constant Qox = 14232475876760437187555678371073865360567175818750566973123447255794615727867;
uint256 constant Qoy = 12884948380030714721172201264029036846611910042838904312559968631894569296588;
uint256 constant Qcx = 14611255151810715369553599153356422265550902840832241273629187752840438096443;
uint256 constant Qcy = 9099095607583972457036848580058361056377035074964862926640921566382822995435;
uint256 constant S1x = 14533465958261944855196820716374074689704505288368818447966063234824080424576;
uint256 constant S1y = 12453353674569653145950160230568106433424266373528956571501497772329286407421;
uint256 constant S2x = 19581287390493194877650947725652399954855738146667446650367315521331119724530;
uint256 constant S2y = 13292535777423157488265774466403939589622049710743071078999542362804505686482;
uint256 constant S3x = 7628615832235497959754170049702774596960536866278288444040861507702299255530;
uint256 constant S3y = 6061093738111279431632848690609155827426019335581022466737969401920480256170;
uint256 constant k1 = 2;
uint256 constant k2 = 3;
uint256 constant X2x1 = 18029695676650738226693292988307914797657423701064905010927197838374790804409;
uint256 constant X2x2 = 14583779054894525174450323658765874724019480979794335525732096752006891875705;
uint256 constant X2y1 = 2140229616977736810657479771656733941598412651537078903776637920509952744750;
uint256 constant X2y2 = 11474861747383700316476719153975578001603231366361248090558603872215261634898;
uint256 constant q = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 constant qf = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
uint256 constant w1 = 19540430494807482326159819597004422086093766032135589407132600596362845576832;
uint256 constant G1x = 1;
uint256 constant G1y = 2;
uint256 constant G2x1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant G2x2 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 constant G2y1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant G2y2 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint16 constant pA = 32;
uint16 constant pB = 96;
uint16 constant pC = 160;
uint16 constant pZ = 224;
uint16 constant pT1 = 288;
uint16 constant pT2 = 352;
uint16 constant pT3 = 416;
uint16 constant pWxi = 480;
uint16 constant pWxiw = 544;
uint16 constant pEval_a = 608;
uint16 constant pEval_b = 640;
uint16 constant pEval_c = 672;
uint16 constant pEval_s1 = 704;
uint16 constant pEval_s2 = 736;
uint16 constant pEval_zw = 768;
uint16 constant pEval_r = 800;
uint16 constant pAlpha = 0;
uint16 constant pBeta = 32;
uint16 constant pGamma = 64;
uint16 constant pXi = 96;
uint16 constant pXin = 128;
uint16 constant pBetaXi = 160;
uint16 constant pV1 = 192;
uint16 constant pV2 = 224;
uint16 constant pV3 = 256;
uint16 constant pV4 = 288;
uint16 constant pV5 = 320;
uint16 constant pV6 = 352;
uint16 constant pU = 384;
uint16 constant pPl = 416;
uint16 constant pEval_t = 448;
uint16 constant pA1 = 480;
uint16 constant pB1 = 544;
uint16 constant pZh = 608;
uint16 constant pZhInv = 640;
uint16 constant pEval_l1 = 672;
uint16 constant pEval_l2 = 704;
uint16 constant lastMem = 736;
function verifyProof(bytes memory proof, uint[] memory pubSignals) public view returns (bool) {
assembly {
/////////
// Computes the inverse using the extended euclidean algorithm
/////////
function inverse(a, q) -> inv {
let t := 0
let newt := 1
let r := q
let newr := a
let quotient
let aux
for { } newr { } {
quotient := sdiv(r, newr)
aux := sub(t, mul(quotient, newt))
t:= newt
newt:= aux
aux := sub(r,mul(quotient, newr))
r := newr
newr := aux
}
if gt(r, 1) { revert(0,0) }
if slt(t, 0) { t:= add(t, q) }
inv := t
}
///////
// Computes the inverse of an array of values
// See https://vitalik.ca/general/2018/07/21/starks_part_3.html in section where explain fields operations
//////
function inverseArray(pVals, n) {
let pAux := mload(0x40) // Point to the next free position
let pIn := pVals
let lastPIn := add(pVals, mul(n, 32)) // Read n elemnts
let acc := mload(pIn) // Read the first element
pIn := add(pIn, 32) // Point to the second element
let inv
for { } lt(pIn, lastPIn) {
pAux := add(pAux, 32)
pIn := add(pIn, 32)
}
{
mstore(pAux, acc)
acc := mulmod(acc, mload(pIn), q)
}
acc := inverse(acc, q)
// At this point pAux pint to the next free position we substract 1 to point to the last used
pAux := sub(pAux, 32)
// pIn points to the n+1 element, we substract to point to n
pIn := sub(pIn, 32)
lastPIn := pVals // We don't process the first element
for { } gt(pIn, lastPIn) {
pAux := sub(pAux, 32)
pIn := sub(pIn, 32)
}
{
inv := mulmod(acc, mload(pAux), q)
acc := mulmod(acc, mload(pIn), q)
mstore(pIn, inv)
}
// pIn points to first element, we just set it.
mstore(pIn, acc)
}
function checkField(v) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0,0x20)
}
}
function checkInput(pProof) {
if iszero(eq(mload(pProof), 800 )) {
mstore(0, 0)
return(0,0x20)
}
checkField(mload(add(pProof, pEval_a)))
checkField(mload(add(pProof, pEval_b)))
checkField(mload(add(pProof, pEval_c)))
checkField(mload(add(pProof, pEval_s1)))
checkField(mload(add(pProof, pEval_s2)))
checkField(mload(add(pProof, pEval_zw)))
checkField(mload(add(pProof, pEval_r)))
// Points are checked in the point operations precompiled smart contracts
}
function calculateChallanges(pProof, pMem) {
let a
let b
b := mod(keccak256(add(pProof, pA), 192), q)
mstore( add(pMem, pBeta), b)
mstore( add(pMem, pGamma), mod(keccak256(add(pMem, pBeta), 32), q))
mstore( add(pMem, pAlpha), mod(keccak256(add(pProof, pZ), 64), q))
a := mod(keccak256(add(pProof, pT1), 192), q)
mstore( add(pMem, pXi), a)
mstore( add(pMem, pBetaXi), mulmod(b, a, q))
a:= mulmod(a, a, q)
a:= mulmod(a, a, q)
a:= mulmod(a, a, q)
mstore( add(pMem, pXin), a)
a:= mod(add(sub(a, 1),q), q)
mstore( add(pMem, pZh), a)
mstore( add(pMem, pZhInv), a) // We will invert later together with lagrange pols
let v1 := mod(keccak256(add(pProof, pEval_a), 224), q)
mstore( add(pMem, pV1), v1)
a := mulmod(v1, v1, q)
mstore( add(pMem, pV2), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV3), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV4), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV5), a)
a := mulmod(a, v1, q)
mstore( add(pMem, pV6), a)
mstore( add(pMem, pU), mod(keccak256(add(pProof, pWxi), 128), q))
}
function calculateLagrange(pMem) {
let w := 1
mstore(
add(pMem, pEval_l1),
mulmod(
n,
mod(
add(
sub(
mload(add(pMem, pXi)),
w
),
q
),
q
),
q
)
)
w := mulmod(w, w1, q)
mstore(
add(pMem, pEval_l2),
mulmod(
n,
mod(
add(
sub(
mload(add(pMem, pXi)),
w
),
q
),
q
),
q
)
)
inverseArray(add(pMem, pZhInv), 3 )
let zh := mload(add(pMem, pZh))
w := 1
mstore(
add(pMem, pEval_l1 ),
mulmod(
mload(add(pMem, pEval_l1 )),
zh,
q
)
)
w := mulmod(w, w1, q)
mstore(
add(pMem, pEval_l2),
mulmod(
w,
mulmod(
mload(add(pMem, pEval_l2)),
zh,
q
),
q
)
)
}
function calculatePl(pMem, pPub) {
let pl := 0
pl := mod(
add(
sub(
pl,
mulmod(
mload(add(pMem, pEval_l1)),
mload(add(pPub, 32)),
q
)
),
q
),
q
)
pl := mod(
add(
sub(
pl,
mulmod(
mload(add(pMem, pEval_l2)),
mload(add(pPub, 64)),
q
)
),
q
),
q
)
mstore(add(pMem, pPl), pl)
}
function calculateT(pProof, pMem) {
let t
let t1
let t2
t := addmod(
mload(add(pProof, pEval_r)),
mload(add(pMem, pPl)),
q
)
t1 := mulmod(
mload(add(pProof, pEval_s1)),
mload(add(pMem, pBeta)),
q
)
t1 := addmod(
t1,
mload(add(pProof, pEval_a)),
q
)
t1 := addmod(
t1,
mload(add(pMem, pGamma)),
q
)
t2 := mulmod(
mload(add(pProof, pEval_s2)),
mload(add(pMem, pBeta)),
q
)
t2 := addmod(
t2,
mload(add(pProof, pEval_b)),
q
)
t2 := addmod(
t2,
mload(add(pMem, pGamma)),
q
)
t1 := mulmod(t1, t2, q)
t2 := addmod(
mload(add(pProof, pEval_c)),
mload(add(pMem, pGamma)),
q
)
t1 := mulmod(t1, t2, q)
t1 := mulmod(t1, mload(add(pProof, pEval_zw)), q)
t1 := mulmod(t1, mload(add(pMem, pAlpha)), q)
t2 := mulmod(
mload(add(pMem, pEval_l1)),
mload(add(pMem, pAlpha)),
q
)
t2 := mulmod(
t2,
mload(add(pMem, pAlpha)),
q
)
t1 := addmod(t1, t2, q)
t := mod(sub(add(t, q), t1), q)
t := mulmod(t, mload(add(pMem, pZhInv)), q)
mstore( add(pMem, pEval_t) , t)
}
function g1_set(pR, pP) {
mstore(pR, mload(pP))
mstore(add(pR, 32), mload(add(pP,32)))
}
function g1_acc(pR, pP) {
let mIn := mload(0x40)
mstore(mIn, mload(pR))
mstore(add(mIn,32), mload(add(pR, 32)))
mstore(add(mIn,64), mload(pP))
mstore(add(mIn,96), mload(add(pP, 32)))
let success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function g1_mulAcc(pR, pP, s) {
let success
let mIn := mload(0x40)
mstore(mIn, mload(pP))
mstore(add(mIn,32), mload(add(pP, 32)))
mstore(add(mIn,64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
mstore(add(mIn,64), mload(pR))
mstore(add(mIn,96), mload(add(pR, 32)))
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function g1_mulAccC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn,32), y)
mstore(add(mIn,64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
mstore(add(mIn,64), mload(pR))
mstore(add(mIn,96), mload(add(pR, 32)))
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function g1_mulSetC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn,32), y)
mstore(add(mIn,64), s)
success := staticcall(sub(gas(), 2000), 7, mIn, 96, pR, 64)
if iszero(success) {
mstore(0, 0)
return(0,0x20)
}
}
function calculateA1(pProof, pMem) {
let p := add(pMem, pA1)
g1_set(p, add(pProof, pWxi))
g1_mulAcc(p, add(pProof, pWxiw), mload(add(pMem, pU)))
}
function calculateB1(pProof, pMem) {
let s
let s1
let p := add(pMem, pB1)
// Calculate D
s := mulmod( mload(add(pProof, pEval_a)), mload(add(pMem, pV1)), q)
g1_mulSetC(p, Qlx, Qly, s)
s := mulmod( s, mload(add(pProof, pEval_b)), q)
g1_mulAccC(p, Qmx, Qmy, s)
s := mulmod( mload(add(pProof, pEval_b)), mload(add(pMem, pV1)), q)
g1_mulAccC(p, Qrx, Qry, s)
s := mulmod( mload(add(pProof, pEval_c)), mload(add(pMem, pV1)), q)
g1_mulAccC(p, Qox, Qoy, s)
s :=mload(add(pMem, pV1))
g1_mulAccC(p, Qcx, Qcy, s)
s := addmod(mload(add(pProof, pEval_a)), mload(add(pMem, pBetaXi)), q)
s := addmod(s, mload(add(pMem, pGamma)), q)
s1 := mulmod(k1, mload(add(pMem, pBetaXi)), q)
s1 := addmod(s1, mload(add(pProof, pEval_b)), q)
s1 := addmod(s1, mload(add(pMem, pGamma)), q)
s := mulmod(s, s1, q)
s1 := mulmod(k2, mload(add(pMem, pBetaXi)), q)
s1 := addmod(s1, mload(add(pProof, pEval_c)), q)
s1 := addmod(s1, mload(add(pMem, pGamma)), q)
s := mulmod(s, s1, q)
s := mulmod(s, mload(add(pMem, pAlpha)), q)
s := mulmod(s, mload(add(pMem, pV1)), q)
s1 := mulmod(mload(add(pMem, pEval_l1)), mload(add(pMem, pAlpha)), q)
s1 := mulmod(s1, mload(add(pMem, pAlpha)), q)
s1 := mulmod(s1, mload(add(pMem, pV1)), q)
s := addmod(s, s1, q)
s := addmod(s, mload(add(pMem, pU)), q)
g1_mulAcc(p, add(pProof, pZ), s)
s := mulmod(mload(add(pMem, pBeta)), mload(add(pProof, pEval_s1)), q)
s := addmod(s, mload(add(pProof, pEval_a)), q)
s := addmod(s, mload(add(pMem, pGamma)), q)
s1 := mulmod(mload(add(pMem, pBeta)), mload(add(pProof, pEval_s2)), q)
s1 := addmod(s1, mload(add(pProof, pEval_b)), q)
s1 := addmod(s1, mload(add(pMem, pGamma)), q)
s := mulmod(s, s1, q)
s := mulmod(s, mload(add(pMem, pAlpha)), q)
s := mulmod(s, mload(add(pMem, pV1)), q)
s := mulmod(s, mload(add(pMem, pBeta)), q)
s := mulmod(s, mload(add(pProof, pEval_zw)), q)
s := mod(sub(q, s), q)
g1_mulAccC(p, S3x, S3y, s)
// calculate F
g1_acc(p , add(pProof, pT1))
s := mload(add(pMem, pXin))
g1_mulAcc(p, add(pProof, pT2), s)
s := mulmod(s, s, q)
g1_mulAcc(p, add(pProof, pT3), s)
g1_mulAcc(p, add(pProof, pA), mload(add(pMem, pV2)))
g1_mulAcc(p, add(pProof, pB), mload(add(pMem, pV3)))
g1_mulAcc(p, add(pProof, pC), mload(add(pMem, pV4)))
g1_mulAccC(p, S1x, S1y, mload(add(pMem, pV5)))
g1_mulAccC(p, S2x, S2y, mload(add(pMem, pV6)))
// calculate E
s := mload(add(pMem, pEval_t))
s := addmod(s, mulmod(mload(add(pProof, pEval_r)), mload(add(pMem, pV1)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_a)), mload(add(pMem, pV2)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_b)), mload(add(pMem, pV3)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_c)), mload(add(pMem, pV4)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_s1)), mload(add(pMem, pV5)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_s2)), mload(add(pMem, pV6)), q), q)
s := addmod(s, mulmod(mload(add(pProof, pEval_zw)), mload(add(pMem, pU)), q), q)
s := mod(sub(q, s), q)
g1_mulAccC(p, G1x, G1y, s)
// Last part of B
s := mload(add(pMem, pXi))
g1_mulAcc(p, add(pProof, pWxi), s)
s := mulmod(mload(add(pMem, pU)), mload(add(pMem, pXi)), q)
s := mulmod(s, w1, q)
g1_mulAcc(p, add(pProof, pWxiw), s)
}
function checkPairing(pMem) -> isOk {
let mIn := mload(0x40)
mstore(mIn, mload(add(pMem, pA1)))
mstore(add(mIn,32), mload(add(add(pMem, pA1), 32)))
mstore(add(mIn,64), X2x2)
mstore(add(mIn,96), X2x1)
mstore(add(mIn,128), X2y2)
mstore(add(mIn,160), X2y1)
mstore(add(mIn,192), mload(add(pMem, pB1)))
let s := mload(add(add(pMem, pB1), 32))
s := mod(sub(qf, s), qf)
mstore(add(mIn,224), s)
mstore(add(mIn,256), G2x2)
mstore(add(mIn,288), G2x1)
mstore(add(mIn,320), G2y2)
mstore(add(mIn,352), G2y1)
let success := staticcall(sub(gas(), 2000), 8, mIn, 384, mIn, 0x20)
isOk := and(success, mload(mIn))
}
let pMem := mload(0x40)
mstore(0x40, add(pMem, lastMem))
checkInput(proof)
calculateChallanges(proof, pMem)
calculateLagrange(pMem)
calculatePl(pMem, pubSignals)
calculateT(proof, pMem)
calculateA1(proof, pMem)
calculateB1(proof, pMem)
let isValid := checkPairing(pMem)
mstore(0x40, sub(pMem, lastMem))
mstore(0, isValid)
return(0,0x20)
}
}
}

Binary file not shown.