diff --git a/apps/circuit-compiler/src/app/actions/constant.ts b/apps/circuit-compiler/src/app/actions/constant.ts new file mode 100644 index 0000000000..6dc9ffcff0 --- /dev/null +++ b/apps/circuit-compiler/src/app/actions/constant.ts @@ -0,0 +1,962 @@ +export const GROTH16_VERIFIER = `// 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 . +*/ + +pragma solidity >=0.7.0 <0.9.0; + +contract Groth16Verifier { + // Scalar field size + uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // Verification Key data + uint256 constant alphax = <%= vk_alpha_1[0] %>; + uint256 constant alphay = <%= vk_alpha_1[1] %>; + uint256 constant betax1 = <%= vk_beta_2[0][1] %>; + uint256 constant betax2 = <%= vk_beta_2[0][0] %>; + uint256 constant betay1 = <%= vk_beta_2[1][1] %>; + uint256 constant betay2 = <%= vk_beta_2[1][0] %>; + uint256 constant gammax1 = <%= vk_gamma_2[0][1] %>; + uint256 constant gammax2 = <%= vk_gamma_2[0][0] %>; + uint256 constant gammay1 = <%= vk_gamma_2[1][1] %>; + uint256 constant gammay2 = <%= vk_gamma_2[1][0] %>; + uint256 constant deltax1 = <%= vk_delta_2[0][1] %>; + uint256 constant deltax2 = <%= vk_delta_2[0][0] %>; + uint256 constant deltay1 = <%= vk_delta_2[1][1] %>; + uint256 constant deltay2 = <%= vk_delta_2[1][0] %>; + + <% for (let i=0; i + uint256 constant IC<%=i%>x = <%=IC[i][0]%>; + uint256 constant IC<%=i%>y = <%=IC[i][1]%>; + <% } %> + + // Memory data + uint16 constant pVk = 0; + uint16 constant pPairing = 128; + + uint16 constant pLastMem = 896; + + function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[<%=IC.length-1%>] calldata _pubSignals) public view returns (bool) { + assembly { + function checkField(v) { + if iszero(lt(v, q)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + 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 checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk { + let _pPairing := add(pMem, pPairing) + let _pVk := add(pMem, pVk) + + mstore(_pVk, IC0x) + mstore(add(_pVk, 32), IC0y) + + // Compute the linear combination vk_x + <% for (let i = 1; i <= nPublic; i++) { %> + g1_mulAccC(_pVk, IC<%=i%>x, IC<%=i%>y, calldataload(add(pubSignals, <%=(i-1)*32%>))) + <% } %> + + // -A + mstore(_pPairing, calldataload(pA)) + mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q)) + + // B + mstore(add(_pPairing, 64), calldataload(pB)) + mstore(add(_pPairing, 96), calldataload(add(pB, 32))) + mstore(add(_pPairing, 128), calldataload(add(pB, 64))) + mstore(add(_pPairing, 160), calldataload(add(pB, 96))) + + // alpha1 + mstore(add(_pPairing, 192), alphax) + mstore(add(_pPairing, 224), alphay) + + // beta2 + mstore(add(_pPairing, 256), betax1) + mstore(add(_pPairing, 288), betax2) + mstore(add(_pPairing, 320), betay1) + mstore(add(_pPairing, 352), betay2) + + // vk_x + mstore(add(_pPairing, 384), mload(add(pMem, pVk))) + mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32)))) + + + // gamma2 + mstore(add(_pPairing, 448), gammax1) + mstore(add(_pPairing, 480), gammax2) + mstore(add(_pPairing, 512), gammay1) + mstore(add(_pPairing, 544), gammay2) + + // C + mstore(add(_pPairing, 576), calldataload(pC)) + mstore(add(_pPairing, 608), calldataload(add(pC, 32))) + + // delta2 + mstore(add(_pPairing, 640), deltax1) + mstore(add(_pPairing, 672), deltax2) + mstore(add(_pPairing, 704), deltay1) + mstore(add(_pPairing, 736), deltay2) + + + let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20) + + isOk := and(success, mload(_pPairing)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, pLastMem)) + + // Validate that all evaluations ∈ F + <% for (let i=0; i + checkField(calldataload(add(_pubSignals, <%=i*32%>))) + <% } %> + + // Validate all evaluations + let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } + }` + +export const PLONK_VERIFIER = `// 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 . +*/ + + +pragma solidity >=0.7.0 <0.9.0; + +import "hardhat/console.sol"; + +contract PlonkVerifier { + // Omega + uint256 constant w1 = <%=w%>; + // Scalar field size + uint256 constant q = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant qf = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // [1]_1 + uint256 constant G1x = 1; + uint256 constant G1y = 2; + // [1]_2 + uint256 constant G2x1 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant G2x2 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant G2y1 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant G2y2 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; + + // Verification Key data + uint32 constant n = <%=2**power%>; + uint16 constant nPublic = <%=nPublic%>; + uint16 constant nLagrange = <%=Math.max(nPublic, 1)%>; + + uint256 constant Qmx = <%=Qm[0]%>; + uint256 constant Qmy = <%=Qm[0] == "0" ? "0" : Qm[1]%>; + uint256 constant Qlx = <%=Ql[0]%>; + uint256 constant Qly = <%=Ql[0] == "0" ? "0" : Ql[1]%>; + uint256 constant Qrx = <%=Qr[0]%>; + uint256 constant Qry = <%=Qr[0] == "0" ? "0" : Qr[1]%>; + uint256 constant Qox = <%=Qo[0]%>; + uint256 constant Qoy = <%=Qo[0] == "0" ? "0" : Qo[1]%>; + uint256 constant Qcx = <%=Qc[0]%>; + uint256 constant Qcy = <%=Qc[0] == "0" ? "0" : Qc[1]%>; + uint256 constant S1x = <%=S1[0]%>; + uint256 constant S1y = <%=S1[0] == "0" ? "0" : S1[1]%>; + uint256 constant S2x = <%=S2[0]%>; + uint256 constant S2y = <%=S2[0] == "0" ? "0" : S2[1]%>; + uint256 constant S3x = <%=S3[0]%>; + uint256 constant S3y = <%=S3[0] == "0" ? "0" : S3[1]%>; + uint256 constant k1 = <%=k1%>; + uint256 constant k2 = <%=k2%>; + 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]%>; + + // Proof calldata + // Byte offset of every parameter of the calldata + // Polynomial commitments + uint16 constant pA = 4 + 0; + uint16 constant pB = 4 + 64; + uint16 constant pC = 4 + 128; + uint16 constant pZ = 4 + 192; + uint16 constant pT1 = 4 + 256; + uint16 constant pT2 = 4 + 320; + uint16 constant pT3 = 4 + 384; + uint16 constant pWxi = 4 + 448; + uint16 constant pWxiw = 4 + 512; + // Opening evaluations + uint16 constant pEval_a = 4 + 576; + uint16 constant pEval_b = 4 + 608; + uint16 constant pEval_c = 4 + 640; + uint16 constant pEval_s1 = 4 + 672; + uint16 constant pEval_s2 = 4 + 704; + uint16 constant pEval_zw = 4 + 736; + + // Memory data + // Challenges + 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 pU = 352; + + uint16 constant pPI = 384; + uint16 constant pEval_r0 = 416; + uint16 constant pD = 448; + uint16 constant pF = 512; + uint16 constant pE = 576; + uint16 constant pTmp = 640; + uint16 constant pAlpha2 = 704; + uint16 constant pZh = 736; + uint16 constant pZhInv = 768; + + <% for (let i=1; i<=Math.max(nPublic, 1); i++) { %> + uint16 constant pEval_l<%=i%> = <%=768+i*32%>; + <% } %> + <% let pLastMem = 800+32*Math.max(nPublic,1) %> + + uint16 constant lastMem = <%=pLastMem%>; + + function verifyProof(uint256[24] calldata _proof, uint256[<%=nPublic%>] calldata _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 elements + 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 subtract 1 to point to the last used + pAux := sub(pAux, 32) + // pIn points to the n+1 element, we subtract 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() { + checkField(calldataload(pEval_a)) + checkField(calldataload(pEval_b)) + checkField(calldataload(pEval_c)) + checkField(calldataload(pEval_s1)) + checkField(calldataload(pEval_s2)) + checkField(calldataload(pEval_zw)) + } + + function calculateChallenges(pMem, pPublic) { + let beta + let aux + + let mIn := mload(0x40) // Pointer to the next free memory position + + // Compute challenge.beta & challenge.gamma + mstore(mIn, Qmx) + mstore(add(mIn, 32), Qmy) + mstore(add(mIn, 64), Qlx) + mstore(add(mIn, 96), Qly) + mstore(add(mIn, 128), Qrx) + mstore(add(mIn, 160), Qry) + mstore(add(mIn, 192), Qox) + mstore(add(mIn, 224), Qoy) + mstore(add(mIn, 256), Qcx) + mstore(add(mIn, 288), Qcy) + mstore(add(mIn, 320), S1x) + mstore(add(mIn, 352), S1y) + mstore(add(mIn, 384), S2x) + mstore(add(mIn, 416), S2y) + mstore(add(mIn, 448), S3x) + mstore(add(mIn, 480), S3y) + + <%for (let i=0; i + mstore(add(mIn, <%= 512 + i*32 %>), calldataload(add(pPublic, <%=i*32%>))) + <%}%> + mstore(add(mIn, <%= 512 + nPublic*32 + 0 %> ), calldataload(pA)) + mstore(add(mIn, <%= 512 + nPublic*32 + 32 %> ), calldataload(add(pA, 32))) + mstore(add(mIn, <%= 512 + nPublic*32 + 64 %> ), calldataload(pB)) + mstore(add(mIn, <%= 512 + nPublic*32 + 96 %> ), calldataload(add(pB, 32))) + mstore(add(mIn, <%= 512 + nPublic*32 + 128 %> ), calldataload(pC)) + mstore(add(mIn, <%= 512 + nPublic*32 + 160 %> ), calldataload(add(pC, 32))) + + beta := mod(keccak256(mIn, <%= 704 + 32 * nPublic %>), q) + mstore(add(pMem, pBeta), beta) + + // challenges.gamma + mstore(add(pMem, pGamma), mod(keccak256(add(pMem, pBeta), 32), q)) + + // challenges.alpha + mstore(mIn, mload(add(pMem, pBeta))) + mstore(add(mIn, 32), mload(add(pMem, pGamma))) + mstore(add(mIn, 64), calldataload(pZ)) + mstore(add(mIn, 96), calldataload(add(pZ, 32))) + + aux := mod(keccak256(mIn, 128), q) + mstore(add(pMem, pAlpha), aux) + mstore(add(pMem, pAlpha2), mulmod(aux, aux, q)) + + // challenges.xi + mstore(mIn, aux) + mstore(add(mIn, 32), calldataload(pT1)) + mstore(add(mIn, 64), calldataload(add(pT1, 32))) + mstore(add(mIn, 96), calldataload(pT2)) + mstore(add(mIn, 128), calldataload(add(pT2, 32))) + mstore(add(mIn, 160), calldataload(pT3)) + mstore(add(mIn, 192), calldataload(add(pT3, 32))) + + aux := mod(keccak256(mIn, 224), q) + mstore( add(pMem, pXi), aux) + + // challenges.v + mstore(mIn, aux) + mstore(add(mIn, 32), calldataload(pEval_a)) + mstore(add(mIn, 64), calldataload(pEval_b)) + mstore(add(mIn, 96), calldataload(pEval_c)) + mstore(add(mIn, 128), calldataload(pEval_s1)) + mstore(add(mIn, 160), calldataload(pEval_s2)) + mstore(add(mIn, 192), calldataload(pEval_zw)) + + let v1 := mod(keccak256(mIn, 224), q) + mstore(add(pMem, pV1), v1) + + // challenges.beta * challenges.xi + mstore(add(pMem, pBetaXi), mulmod(beta, aux, q)) + + // challenges.xi^n + <%for (let i=0; i + aux:= mulmod(aux, aux, q) + <%}%> + mstore(add(pMem, pXin), aux) + + // Zh + aux:= mod(add(sub(aux, 1), q), q) + mstore(add(pMem, pZh), aux) + mstore(add(pMem, pZhInv), aux) // We will invert later together with lagrange pols + + // challenges.v^2, challenges.v^3, challenges.v^4, challenges.v^5 + aux := mulmod(v1, v1, q) + mstore(add(pMem, pV2), aux) + aux := mulmod(aux, v1, q) + mstore(add(pMem, pV3), aux) + aux := mulmod(aux, v1, q) + mstore(add(pMem, pV4), aux) + aux := mulmod(aux, v1, q) + mstore(add(pMem, pV5), aux) + + // challenges.u + mstore(mIn, calldataload(pWxi)) + mstore(add(mIn, 32), calldataload(add(pWxi, 32))) + mstore(add(mIn, 64), calldataload(pWxiw)) + mstore(add(mIn, 96), calldataload(add(pWxiw, 32))) + + mstore(add(pMem, pU), mod(keccak256(mIn, 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 + 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 + w := mulmod(w, w1, q) + <% } %> + <% } %> + + + } + + function calculatePI(pMem, pPub) { + let pl := 0 + + <% for (let i=0; i + pl := mod( + add( + sub( + pl, + mulmod( + mload(add(pMem, pEval_l<%=i+1%>)), + calldataload(add(pPub, <%=i*32%>)), + q + ) + ), + q + ), + q + ) + <% } %> + + mstore(add(pMem, pPI), pl) + } + + function calculateR0(pMem) { + let e1 := mload(add(pMem, pPI)) + + let e2 := mulmod(mload(add(pMem, pEval_l1)), mload(add(pMem, pAlpha2)), q) + + let e3a := addmod( + calldataload(pEval_a), + mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s1), q), + q) + e3a := addmod(e3a, mload(add(pMem, pGamma)), q) + + let e3b := addmod( + calldataload(pEval_b), + mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s2), q), + q) + e3b := addmod(e3b, mload(add(pMem, pGamma)), q) + + let e3c := addmod( + calldataload(pEval_c), + mload(add(pMem, pGamma)), + q) + + let e3 := mulmod(mulmod(e3a, e3b, q), e3c, q) + e3 := mulmod(e3, calldataload(pEval_zw), q) + e3 := mulmod(e3, mload(add(pMem, pAlpha)), q) + + let r0 := addmod(e1, mod(sub(q, e2), q), q) + r0 := addmod(r0, mod(sub(q, e3), q), q) + + mstore(add(pMem, pEval_r0) , r0) + } + + function g1_set(pR, pP) { + mstore(pR, mload(pP)) + mstore(add(pR, 32), mload(add(pP,32))) + } + + function g1_setC(pR, x, y) { + mstore(pR, x) + mstore(add(pR, 32), y) + } + + function g1_calldataSet(pR, pP) { + mstore(pR, calldataload(pP)) + mstore(add(pR, 32), calldataload(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 g1_mulSet(pR, pP, s) { + g1_mulSetC(pR, mload(pP), mload(add(pP, 32)), s) + } + + function calculateD(pMem) { + let _pD:= add(pMem, pD) + let gamma := mload(add(pMem, pGamma)) + let mIn := mload(0x40) + mstore(0x40, add(mIn, 256)) // d1, d2, d3 & d4 (4*64 bytes) + + g1_setC(_pD, Qcx, Qcy) + g1_mulAccC(_pD, Qmx, Qmy, mulmod(calldataload(pEval_a), calldataload(pEval_b), q)) + g1_mulAccC(_pD, Qlx, Qly, calldataload(pEval_a)) + g1_mulAccC(_pD, Qrx, Qry, calldataload(pEval_b)) + g1_mulAccC(_pD, Qox, Qoy, calldataload(pEval_c)) + + let betaxi := mload(add(pMem, pBetaXi)) + let val1 := addmod( + addmod(calldataload(pEval_a), betaxi, q), + gamma, q) + + let val2 := addmod( + addmod( + calldataload(pEval_b), + mulmod(betaxi, k1, q), + q), gamma, q) + + let val3 := addmod( + addmod( + calldataload(pEval_c), + mulmod(betaxi, k2, q), + q), gamma, q) + + let d2a := mulmod( + mulmod(mulmod(val1, val2, q), val3, q), + mload(add(pMem, pAlpha)), + q + ) + + let d2b := mulmod( + mload(add(pMem, pEval_l1)), + mload(add(pMem, pAlpha2)), + q + ) + + // We'll use mIn to save d2 + g1_calldataSet(add(mIn, 192), pZ) + g1_mulSet( + mIn, + add(mIn, 192), + addmod(addmod(d2a, d2b, q), mload(add(pMem, pU)), q)) + + + val1 := addmod( + addmod( + calldataload(pEval_a), + mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s1), q), + q), gamma, q) + + val2 := addmod( + addmod( + calldataload(pEval_b), + mulmod(mload(add(pMem, pBeta)), calldataload(pEval_s2), q), + q), gamma, q) + + val3 := mulmod( + mulmod(mload(add(pMem, pAlpha)), mload(add(pMem, pBeta)), q), + calldataload(pEval_zw), q) + + + // We'll use mIn + 64 to save d3 + g1_mulSetC( + add(mIn, 64), + S3x, + S3y, + mulmod(mulmod(val1, val2, q), val3, q)) + + // We'll use mIn + 128 to save d4 + g1_calldataSet(add(mIn, 128), pT1) + + g1_mulAccC(add(mIn, 128), calldataload(pT2), calldataload(add(pT2, 32)), mload(add(pMem, pXin))) + let xin2 := mulmod(mload(add(pMem, pXin)), mload(add(pMem, pXin)), q) + g1_mulAccC(add(mIn, 128), calldataload(pT3), calldataload(add(pT3, 32)) , xin2) + + g1_mulSetC(add(mIn, 128), mload(add(mIn, 128)), mload(add(mIn, 160)), mload(add(pMem, pZh))) + + mstore(add(add(mIn, 64), 32), mod(sub(qf, mload(add(add(mIn, 64), 32))), qf)) + mstore(add(mIn, 160), mod(sub(qf, mload(add(mIn, 160))), qf)) + g1_acc(_pD, mIn) + g1_acc(_pD, add(mIn, 64)) + g1_acc(_pD, add(mIn, 128)) + } + + function calculateF(pMem) { + let p := add(pMem, pF) + + g1_set(p, add(pMem, pD)) + g1_mulAccC(p, calldataload(pA), calldataload(add(pA, 32)), mload(add(pMem, pV1))) + g1_mulAccC(p, calldataload(pB), calldataload(add(pB, 32)), mload(add(pMem, pV2))) + g1_mulAccC(p, calldataload(pC), calldataload(add(pC, 32)), mload(add(pMem, pV3))) + g1_mulAccC(p, S1x, S1y, mload(add(pMem, pV4))) + g1_mulAccC(p, S2x, S2y, mload(add(pMem, pV5))) + } + + function calculateE(pMem) { + let s := mod(sub(q, mload(add(pMem, pEval_r0))), q) + + s := addmod(s, mulmod(calldataload(pEval_a), mload(add(pMem, pV1)), q), q) + s := addmod(s, mulmod(calldataload(pEval_b), mload(add(pMem, pV2)), q), q) + s := addmod(s, mulmod(calldataload(pEval_c), mload(add(pMem, pV3)), q), q) + s := addmod(s, mulmod(calldataload(pEval_s1), mload(add(pMem, pV4)), q), q) + s := addmod(s, mulmod(calldataload(pEval_s2), mload(add(pMem, pV5)), q), q) + s := addmod(s, mulmod(calldataload(pEval_zw), mload(add(pMem, pU)), q), q) + + g1_mulSetC(add(pMem, pE), G1x, G1y, s) + } + + function checkPairing(pMem) -> isOk { + let mIn := mload(0x40) + mstore(0x40, add(mIn, 576)) // [0..383] = pairing data, [384..447] = pWxi, [448..512] = pWxiw + + let _pWxi := add(mIn, 384) + let _pWxiw := add(mIn, 448) + let _aux := add(mIn, 512) + + g1_calldataSet(_pWxi, pWxi) + g1_calldataSet(_pWxiw, pWxiw) + + // A1 + g1_mulSet(mIn, _pWxiw, mload(add(pMem, pU))) + g1_acc(mIn, _pWxi) + mstore(add(mIn, 32), mod(sub(qf, mload(add(mIn, 32))), qf)) + + // [X]_2 + mstore(add(mIn,64), X2x2) + mstore(add(mIn,96), X2x1) + mstore(add(mIn,128), X2y2) + mstore(add(mIn,160), X2y1) + + // B1 + g1_mulSet(add(mIn, 192), _pWxi, mload(add(pMem, pXi))) + + let s := mulmod(mload(add(pMem, pU)), mload(add(pMem, pXi)), q) + s := mulmod(s, w1, q) + g1_mulSet(_aux, _pWxiw, s) + g1_acc(add(mIn, 192), _aux) + g1_acc(add(mIn, 192), add(pMem, pF)) + mstore(add(pMem, add(pE, 32)), mod(sub(qf, mload(add(pMem, add(pE, 32)))), qf)) + g1_acc(add(mIn, 192), add(pMem, pE)) + + // [1]_2 + 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() + calculateChallenges(pMem, _pubSignals) + calculateLagrange(pMem) + calculatePI(pMem, _pubSignals) + calculateR0(pMem) + calculateD(pMem) + calculateF(pMem) + calculateE(pMem) + let isValid := checkPairing(pMem) + + mstore(0x40, sub(pMem, lastMem)) + mstore(0, isValid) + return(0,0x20) + } + + } +}` + +export const PTAU_LIST = [ + { + name: "final_8.ptau", + power: 8, + maxConstraint: "246", + ipfsHash: "QmNwT4UN6gT7vdDPNjmpShEVVbhi6C7tR6Y98X4aCT7sbq", + blake2bHash: null + }, + { + name: "final_9.ptau", + power: 9, + maxConstraint: "512", + ipfsHash: "QmSBtobA8c27Yf2ypTpNtLxxxuadFzyQGksg7un2kN56yN", + blake2bHash: null + }, + { + name: "final_10.ptau", + power: 10, + maxConstraint: "1k", + ipfsHash: "QmQ4dLmm3rRJKAm8CiVUedKu6xFNYsFD4UMVoSrD59jgHa", + blake2bHash: null + }, + { + name: "final_11.ptau", + power: 11, + maxConstraint: "2k", + ipfsHash: "QmdRRJBznWaRnnpSnVcsdJ2RFQLxpVYbeMec3Fwf246MqU", + blake2bHash: null + }, + { + name: "final_12.ptau", + power: 12, + maxConstraint: "4k", + ipfsHash: "Qmdge3jmta3qhGa61Da5UwVBcib6rgkqqHugQCgoT9hutS", + blake2bHash: null + }, + { + name: "final_13.ptau", + power: 13, + maxConstraint: "8k", + ipfsHash: "QmUyXX6qYoExJ5pxyYiukmBSDkwqavUBBHaH2JDYVJX454", + blake2bHash: null + }, + { + name: "final_14.ptau", + power: 14, + maxConstraint: "16k", + ipfsHash: "QmTiT4eiYz5KF7gQrDsgfCSTRv3wBPYJ4bRN1MmTRshpnW", + blake2bHash: null + }, + { + name: "final_15.ptau", + power: 15, + maxConstraint: "32k", + ipfsHash: "QmeWPz6XMLX8HZwkRiiUffC5ziuiaHwNex6KUshpyLFpDg", + blake2bHash: null + }, + { + name: "final_16.ptau", + power: 16, + maxConstraint: "64k", + ipfsHash: "QmVEbbVbBAgciBwGrNCx5HUJhQtatLVSEt54DZcrodYM3G", + blake2bHash: null + }, + { + name: "final_17.ptau", + power: 17, + maxConstraint: "128k", + ipfsHash: "QmciCq5JcZQyTLvC9GRanrLBi82ZmSriq1Fr5zANkGHebf", + blake2bHash: null + }, + { + name: "final_18.ptau", + power: 18, + maxConstraint: "256k", + ipfsHash: "QmRXbrYrrX2oA1FFRFivNi1TjhKoWv2x15g8PRFyV64UZP", + blake2bHash: null + }, + { + name: "final_20.ptau", + power: 20, + maxConstraint: "1M", + ipfsHash: "QmQbrzmoZn5Ku6ENJmwZ1DMN1taAPgwLnp5TMfuSAz6tfh", + blake2bHash: null + }] diff --git a/apps/circuit-compiler/src/app/actions/index.ts b/apps/circuit-compiler/src/app/actions/index.ts index 7c8e6077c3..a994b18ba1 100644 --- a/apps/circuit-compiler/src/app/actions/index.ts +++ b/apps/circuit-compiler/src/app/actions/index.ts @@ -1,5 +1,8 @@ +import * as snarkjs from 'snarkjs' import type { CircomPluginClient } from "../services/circomPluginClient" -import { Actions, AppState } from "../types" +import { AppState } from "../types" +import { GROTH16_VERIFIER, PLONK_VERIFIER } from './constant' +import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper' export const compileCircuit = async (plugin: CircomPluginClient, appState: AppState) => { try { @@ -9,24 +12,12 @@ export const compileCircuit = async (plugin: CircomPluginClient, appState: AppSt console.log('Existing circuit compilation in progress') } } catch (e) { + plugin.emit('statusChanged', { key: 'error', title: e.message, type: 'error' }) plugin.internalEvents.emit('circuit_compiling_errored', e) console.error(e) } } -export const generateR1cs = async (plugin: CircomPluginClient, appState: AppState) => { - try { - if (appState.status !== "generating") { - await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue }) - } else { - console.log('Existing r1cs generation in progress') - } - } catch (e) { - plugin.internalEvents.emit('circuit_generating_r1cs_errored', e) - console.error('Generating R1CS failed: ', e) - } -} - export const computeWitness = async (plugin: CircomPluginClient, status: string, witnessValues: Record) => { try { if (status !== "computing") { @@ -37,7 +28,51 @@ export const computeWitness = async (plugin: CircomPluginClient, status: string, console.log('Existing witness computation in progress') } } catch (e) { + plugin.emit('statusChanged', { key: 'error', title: e.message, type: 'error' }) plugin.internalEvents.emit('circuit_computing_witness_errored', e) console.error('Computing witness failed: ', e) } } + +export const runSetupAndExport = async (plugin: CircomPluginClient, appState: AppState) => { + const ptau_final = `https://ipfs-cluster.ethdevops.io/ipfs/${appState.ptauList.find(ptau => ptau.name === appState.ptauValue)?.ipfsHash}` + await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue }) + + const fileName = extractNameFromKey(appState.filePath) + const readPath = extractParentFromKey(appState.filePath) + `/.bin/${fileName.replace('.circom', '.r1cs')}` + // @ts-ignore + const r1csBuffer = await plugin.call('fileManager', 'readFile', readPath, { encoding: null }) + // @ts-ignore + const r1cs = new Uint8Array(r1csBuffer) + const zkey_final = { type: "mem" } + + if (appState.provingScheme === 'groth16') { + await snarkjs.zKey.newZKey(r1cs, ptau_final, zkey_final) + if (appState.exportVerificationKey) { + const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final) + await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/verification_key.json`, JSON.stringify(vKey, null, 2)) + // @ts-ignore + await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/zkey_final.txt`, (zkey_final as any).data, { encoding: null }) + } + if (appState.exportVerificationContract) { + const templates = { groth16: GROTH16_VERIFIER } + const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates) + + await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/zk_verifier.sol`, solidityContract) + } + } else if (appState.provingScheme === 'plonk') { + await snarkjs.plonk.setup(r1cs, ptau_final, zkey_final) + if (appState.exportVerificationKey) { + const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final) + await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/verification_key.json`, JSON.stringify(vKey, null, 2)) + // @ts-ignore + await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/zkey_final.txt`, (zkey_final as any).data, { encoding: null }) + } + if (appState.exportVerificationContract) { + const templates = { plonk: PLONK_VERIFIER } + const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates) + + await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/zk_verifier.sol`, solidityContract) + } + } +} diff --git a/apps/circuit-compiler/src/app/app.tsx b/apps/circuit-compiler/src/app/app.tsx index 926345ea51..747d0b89d7 100644 --- a/apps/circuit-compiler/src/app/app.tsx +++ b/apps/circuit-compiler/src/app/app.tsx @@ -50,16 +50,11 @@ function App() { }) plugin.internalEvents.on('circuit_compiling_errored', compilerErrored) - // r1cs events - plugin.internalEvents.on('circuit_generating_r1cs_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'generating' })) - plugin.internalEvents.on('circuit_generating_r1cs_done', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })) - plugin.internalEvents.on('circuit_generating_r1cs_errored', compilerErrored) - // witness events plugin.internalEvents.on('circuit_computing_witness_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'computing' })) plugin.internalEvents.on('circuit_computing_witness_done', () => { dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }) - dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null }) + dispatch({ type: 'SET_COMPUTE_FEEDBACK', payload: null }) }) plugin.internalEvents.on('circuit_computing_witness_errored', compilerErrored) @@ -86,6 +81,7 @@ function App() { if (appState.autoCompile) await compileCircuit(plugin, appState) })() setIsContentChanged(false) + if (appState.setupExportStatus === 'done') dispatch({ type: 'SET_SETUP_EXPORT_STATUS', payload: 'update' }) } }, [appState.autoCompile, isContentChanged]) @@ -118,9 +114,9 @@ function App() { try { const report = JSON.parse(err.message) - dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report }) + dispatch({ type: 'SET_COMPUTE_FEEDBACK', payload: report }) } catch (e) { - dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: err.message }) + dispatch({ type: 'SET_COMPUTE_FEEDBACK', payload: err.message }) } } diff --git a/apps/circuit-compiler/src/app/components/actions.tsx b/apps/circuit-compiler/src/app/components/actions.tsx index 2dca59f985..b555b5304f 100644 --- a/apps/circuit-compiler/src/app/components/actions.tsx +++ b/apps/circuit-compiler/src/app/components/actions.tsx @@ -1,11 +1,9 @@ -import { CompileBtn } from "./compileBtn"; -import { R1CSBtn } from "./r1csBtn"; +import { CompileBtn } from "./compileBtn" export function CircuitActions () { return ( -
+
-
) } \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/compileBtn.tsx b/apps/circuit-compiler/src/app/components/compileBtn.tsx index 50eb6e1f13..25dc686eb1 100644 --- a/apps/circuit-compiler/src/app/components/compileBtn.tsx +++ b/apps/circuit-compiler/src/app/components/compileBtn.tsx @@ -20,18 +20,15 @@ export function CompileBtn () { } > - ) -} \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/setupExports.tsx b/apps/circuit-compiler/src/app/components/setupExports.tsx new file mode 100644 index 0000000000..2116c6a8ec --- /dev/null +++ b/apps/circuit-compiler/src/app/components/setupExports.tsx @@ -0,0 +1,123 @@ +import { CustomTooltip } from "@remix-ui/helper" +import { FormattedMessage } from "react-intl" +import { SetupExportsBtn } from "./setupExportsBtn" +import { useContext } from "react" +import { CircuitAppContext } from "../contexts" +import { runSetupAndExport } from "../actions" + +export function SetupExports () { + const circuitApp = useContext(CircuitAppContext) + + const handleRunSetup = async () => { + try { + circuitApp.dispatch({ type: 'SET_COMPILER_STATUS', payload: 'exporting' }) + await runSetupAndExport(circuitApp.plugin, circuitApp.appState) + circuitApp.dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }) + circuitApp.dispatch({ type: 'SET_SETUP_EXPORT_STATUS', payload: 'done' }) + } catch (e) { + circuitApp.dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' }) + circuitApp.dispatch({ type: 'SET_SETUP_EXPORT_FEEDBACK', payload: e.message }) + console.error(e) + } + } + + return ( +
+
+
+ +
+ circuitApp.dispatch({ type: 'SET_PROVING_SCHEME', payload: 'groth16' })} + value='groth16' + checked={circuitApp.appState.provingScheme === 'groth16'} + readOnly + /> + +
+
+ circuitApp.dispatch({ type: 'SET_PROVING_SCHEME', payload: 'plonk' })} + value='plonk' + checked={circuitApp.appState.provingScheme === 'plonk'} + readOnly + /> + +
+
+
+ + {'To choose the from the list of ptau files'}} + > +
+ +
+
+
+ circuitApp.dispatch({ type: 'SET_EXPORT_VERIFICATION_CONTRACT', payload: !circuitApp.appState.exportVerificationContract })} + checked={circuitApp.appState.exportVerificationContract} + /> + +
+
+ circuitApp.dispatch({ type: 'SET_EXPORT_VERIFICATION_KEY', payload: !circuitApp.appState.exportVerificationKey })} + checked={circuitApp.appState.exportVerificationKey} + /> + +
+ +
+
+
+ ) +} \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/setupExportsBtn.tsx b/apps/circuit-compiler/src/app/components/setupExportsBtn.tsx new file mode 100644 index 0000000000..a1bfdc7691 --- /dev/null +++ b/apps/circuit-compiler/src/app/components/setupExportsBtn.tsx @@ -0,0 +1,34 @@ +import { CustomTooltip, RenderIf } from "@remix-ui/helper" +import { FormattedMessage } from "react-intl" +import { CompilerStatus } from "../types" + +export function SetupExportsBtn ({ handleRunSetup, status }: { handleRunSetup: () => Promise, status: CompilerStatus }) { + return
+ } + > +
+ + + +
+ + + +
+
+ + +} \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/toggler.tsx b/apps/circuit-compiler/src/app/components/toggler.tsx new file mode 100644 index 0000000000..ec90a231a8 --- /dev/null +++ b/apps/circuit-compiler/src/app/components/toggler.tsx @@ -0,0 +1,50 @@ +import { useEffect, useState } from "react" +import { FormattedMessage } from "react-intl" +import { CustomTooltip, RenderIf, RenderIfNot } from "@remix-ui/helper" + +export function Toggler ({ children, title, dataId, show = false, icon, iconTooltip }: { children: JSX.Element, title: string, dataId: string, show?: boolean, icon?: string, iconTooltip?: string }) { + const [toggleExpander, setToggleExpander] = useState(show) + + useEffect(() => { + setToggleExpander(show) + }, [show]) + + const toggleConfigurations = () => { + setToggleExpander(!toggleExpander) + } + + return ( +
+
+
+ +
+
+ + + + + + + + +
+
+ + { children } + +
+ ) +} \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/witness.tsx b/apps/circuit-compiler/src/app/components/witness.tsx index 08f82ca171..0a14537cde 100644 --- a/apps/circuit-compiler/src/app/components/witness.tsx +++ b/apps/circuit-compiler/src/app/components/witness.tsx @@ -34,37 +34,32 @@ export function WitnessSection ({ plugin, signalInputs, status }: {plugin: Circo } return ( -
-
- 0}> - <> - { - signalInputs.map((input, index) => ( -
- - -
- )) - } - - -
-
+
+ 0}> + <> + { + signalInputs.map((input, index) => ( +
+ + +
+ )) + } + + +
) } \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/components/witnessToggler.tsx b/apps/circuit-compiler/src/app/components/witnessToggler.tsx deleted file mode 100644 index 60027c2ebe..0000000000 --- a/apps/circuit-compiler/src/app/components/witnessToggler.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useState } from "react" -import { FormattedMessage } from "react-intl" -import { RenderIf, RenderIfNot } from "@remix-ui/helper" - -export function WitnessToggler ({ children }: { children: JSX.Element }) { - const [toggleExpander, setToggleExpander] = useState(false) - - const toggleConfigurations = () => { - setToggleExpander(!toggleExpander) - } - - return ( -
-
-
- -
-
- - - - - - - - -
-
- - { children } - -
- ) -} \ No newline at end of file diff --git a/apps/circuit-compiler/src/app/reducers/state.ts b/apps/circuit-compiler/src/app/reducers/state.ts index e63b5e5a2a..ceee26f60e 100644 --- a/apps/circuit-compiler/src/app/reducers/state.ts +++ b/apps/circuit-compiler/src/app/reducers/state.ts @@ -1,3 +1,4 @@ +import { PTAU_LIST } from '../actions/constant' import { Actions, AppState } from '../types' import { compiler_list } from 'circom_wasm' @@ -11,7 +12,15 @@ export const appInitialState: AppState = { autoCompile: false, hideWarnings: false, signalInputs: [], - feedback: null + compilerFeedback: null, + computeFeedback: null, + setupExportFeedback: null, + setupExportStatus: null, + provingScheme: 'groth16', + ptauList: PTAU_LIST, + ptauValue: "final_14.ptau", + exportVerificationContract: true, + exportVerificationKey: true } export const appReducer = (state = appInitialState, action: Actions): AppState => { @@ -62,7 +71,19 @@ export const appReducer = (state = appInitialState, action: Actions): AppState = case 'SET_COMPILER_FEEDBACK': return { ...state, - feedback: action.payload + compilerFeedback: action.payload + } + + case 'SET_COMPUTE_FEEDBACK': + return { + ...state, + computeFeedback: action.payload + } + + case 'SET_SETUP_EXPORT_FEEDBACK': + return { + ...state, + setupExportFeedback: action.payload } case 'SET_FILE_PATH_TO_ID': @@ -71,6 +92,36 @@ export const appReducer = (state = appInitialState, action: Actions): AppState = filePathToId: action.payload } + case 'SET_PROVING_SCHEME': + return { + ...state, + provingScheme: action.payload + } + + case 'SET_PTAU_VALUE': + return { + ...state, + ptauValue: action.payload + } + + case 'SET_EXPORT_VERIFICATION_CONTRACT': + return { + ...state, + exportVerificationContract: action.payload + } + + case 'SET_EXPORT_VERIFICATION_KEY': + return { + ...state, + exportVerificationKey: action.payload + } + + case 'SET_SETUP_EXPORT_STATUS': + return { + ...state, + setupExportStatus: action.payload + } + default: throw new Error() } diff --git a/apps/circuit-compiler/src/app/services/circomPluginClient.ts b/apps/circuit-compiler/src/app/services/circomPluginClient.ts index 93a2445861..f6817fe7a5 100644 --- a/apps/circuit-compiler/src/app/services/circomPluginClient.ts +++ b/apps/circuit-compiler/src/app/services/circomPluginClient.ts @@ -197,24 +197,15 @@ export class CircomPluginClient extends PluginClient { } async generateR1cs (path: string, compilationConfig?: CompilationConfig): Promise { - this.internalEvents.emit('circuit_generating_r1cs_start') - this.emit('statusChanged', { key: 'loading', title: 'Generating...', type: 'info' }) - // @ts-ignore - this.call('terminal', 'log', { type: 'log', value: 'Generating R1CS for ' + path }) const [parseErrors, filePathToId] = await this.parse(path) if (parseErrors && (parseErrors.length > 0)) { if (parseErrors[0].type === 'Error') { - this.internalEvents.emit('circuit_parsing_errored', parseErrors) this.logCompilerReport(parseErrors) return } else if (parseErrors[0].type === 'Warning') { - this.internalEvents.emit('circuit_parsing_warning', parseErrors) this.logCompilerReport(parseErrors) } - } else { - this.internalEvents.emit('circuit_parsing_done', parseErrors, filePathToId) - this.emit('statusChanged', { key: 'succeed', title: 'r1cs generated successfully', type: 'success' }) } if (compilationConfig) { const { prime, version } = compilationConfig @@ -232,7 +223,6 @@ export class CircomPluginClient extends PluginClient { this._paq.push(['trackEvent', 'circuit-compiler', 'generateR1cs', 'R1CS Generation failed']) throw new Error(r1csErrors) } else { - this.internalEvents.emit('circuit_generating_r1cs_done') const fileName = extractNameFromKey(path) const writePath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'r1cs') diff --git a/apps/circuit-compiler/src/app/types/index.ts b/apps/circuit-compiler/src/app/types/index.ts index 64f3b3281f..4be4b6a9f6 100644 --- a/apps/circuit-compiler/src/app/types/index.ts +++ b/apps/circuit-compiler/src/app/types/index.ts @@ -2,7 +2,19 @@ import { compiler_list } from 'circom_wasm' import { Dispatch } from 'react' import type { CircomPluginClient } from '../services/circomPluginClient' -export type CompilerStatus = "compiling" | "generating" | "computing" | "idle" | "errored" | "warning" +export type CompilerStatus = "compiling" | "computing" | "idle" | "errored" | "warning" | "exporting" + +export type ProvingScheme = 'groth16' | 'plonk' + +export type SetupExportStatus = 'done' | 'update' + +export type PtauFile = { + name: string, + power: number, + maxConstraint: string, + ipfsHash: string, + blake2bHash: string +} export interface ICircuitAppContext { appState: AppState dispatch: Dispatch, @@ -17,8 +29,15 @@ export interface ActionPayloadTypes { SET_AUTO_COMPILE: boolean, SET_HIDE_WARNINGS: boolean, SET_SIGNAL_INPUTS: string[], - SET_COMPILER_FEEDBACK: string | CompilerReport[] - SET_FILE_PATH_TO_ID: Record + SET_COMPILER_FEEDBACK: string | CompilerReport[], + SET_COMPUTE_FEEDBACK: string | CompilerReport[], + SET_SETUP_EXPORT_FEEDBACK: string | CompilerReport[], + SET_FILE_PATH_TO_ID: Record, + SET_PROVING_SCHEME: ProvingScheme, + SET_PTAU_VALUE: string, + SET_EXPORT_VERIFICATION_CONTRACT: boolean, + SET_EXPORT_VERIFICATION_KEY: boolean, + SET_SETUP_EXPORT_STATUS: SetupExportStatus } export interface Action { type: T @@ -37,7 +56,15 @@ export interface AppState { autoCompile: boolean, hideWarnings: boolean, signalInputs: string[], - feedback: string | CompilerReport[] + compilerFeedback: string | CompilerReport[], + computeFeedback: string | CompilerReport[], + setupExportFeedback: string | CompilerReport[], + setupExportStatus: SetupExportStatus, + provingScheme: ProvingScheme, + ptauList: Array, + ptauValue: string, + exportVerificationContract: boolean, + exportVerificationKey: boolean } export type CompilationConfig = { diff --git a/apps/circuit-compiler/src/css/app.css b/apps/circuit-compiler/src/css/app.css index e901a5ef76..f229a913b4 100644 --- a/apps/circuit-compiler/src/css/app.css +++ b/apps/circuit-compiler/src/css/app.css @@ -37,8 +37,6 @@ body { text-transform: uppercase; } .circuit_errors_box { - padding-left: 5px; - padding-right: 5px; word-break: break-word; } .circuit_feedback.success, diff --git a/apps/circuit-compiler/src/profile.json b/apps/circuit-compiler/src/profile.json index 9ee0e0f0dc..250c519385 100644 --- a/apps/circuit-compiler/src/profile.json +++ b/apps/circuit-compiler/src/profile.json @@ -4,7 +4,7 @@ "displayName": "Circom ZKP compiler", "events": [], "version": "2.0.0", - "methods": ["init", "parse", "compile", "generateR1cs"], + "methods": ["init", "parse", "compile"], "canActivate": [], "url": "", "description": "Enables circuit compilation and computing a witness for ZK proofs", diff --git a/apps/remix-ide-e2e/src/tests/circom.test.ts b/apps/remix-ide-e2e/src/tests/circom.test.ts index ac14415ea9..4b30e815e5 100644 --- a/apps/remix-ide-e2e/src/tests/circom.test.ts +++ b/apps/remix-ide-e2e/src/tests/circom.test.ts @@ -72,17 +72,38 @@ module.exports = { .waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]') .waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.wasm"]') }, - 'Should generate R1CS for a simple circuit #group2': function (browser: NightwatchBrowser) { + 'Should run Groth16 setup and export for a simple circuit using the GUI #group2': function (browser: NightwatchBrowser) { browser .clickLaunchIcon('circuit-compiler') .frame(0) - .waitForElementPresent('button[data-id="generate_r1cs_btn"]') - .waitForElementVisible('button[data-id="generate_r1cs_btn"]') - .click('button[data-id="generate_r1cs_btn"]') + .waitForElementVisible('[data-id="setup_exports_toggler"]') + .waitForElementPresent('[data-id="groth16ProvingScheme"]') + .click('[data-id="groth16ProvingScheme"]') + .waitForElementVisible('[data-id="circuitPtauSelect"]') + .click('[data-id="circuitPtauSelect"]') + .waitForElementVisible('[data-id="dropdown-item-final_8.ptau"]') + .click('[data-id="dropdown-item-final_8.ptau"]') + .click('[data-id="runSetupBtn"]') + .waitForElementVisible('[data-id="setup_exports_toggler"] .fa-check-circle') .frameParent() .clickLaunchIcon('filePanel') - .waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.r1cs"]') - .waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple.r1cs"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/groth16/zk/keys/verification_key.json"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/groth16/zk/keys/zkey_final.txt"]') + }, + 'Should run Plonk setup and export for a simple circuit using the GUI #group2': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('circuit-compiler') + .frame(0) + .waitForElementVisible('[data-id="setup_exports_toggler"]') + .click('[data-id="setup_exports_toggler"]') + .waitForElementPresent('[data-id="plonkProvingScheme"]') + .click('[data-id="plonkProvingScheme"]') + .click('[data-id="runSetupBtn"]') + .waitForElementVisible('[data-id="setup_exports_toggler"] .fa-check-circle') + .frameParent() + .clickLaunchIcon('filePanel') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/plonk/zk/keys/verification_key.json"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/plonk/zk/keys/zkey_final.txt"]') }, 'Should compile a simple circuit using CTRL + S from the editor #group3': function (browser: NightwatchBrowser) { browser @@ -176,10 +197,7 @@ module.exports = { .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') .click('[data-id="play-editor"]') - .pause(2000) - .journalLastChildIncludes('Generating R1CS for circuits/calculate_hash.circom') - .pause(5000) - .journalLastChildIncludes('Everything went okay') + .pause(7000) .journalLastChildIncludes('newZkey') .pause(25000) .journalLastChildIncludes('setup done.') @@ -214,10 +232,7 @@ module.exports = { .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') .click('[data-id="play-editor"]') - .pause(2000) - .journalLastChildIncludes('Generating R1CS for circuits/calculate_hash.circom') - .pause(5000) - .journalLastChildIncludes('Everything went okay') + .pause(7000) .journalLastChildIncludes('plonk setup') .pause(10000) .journalLastChildIncludes('setup done') diff --git a/apps/remix-ide/src/app/tabs/locales/en/circuit.json b/apps/remix-ide/src/app/tabs/locales/en/circuit.json index 61184793f5..4a10ba5f43 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/circuit.json +++ b/apps/remix-ide/src/app/tabs/locales/en/circuit.json @@ -11,5 +11,13 @@ "circuit.generateR1cs": "Generate R1CS", "circuit.computeWitness": "Compute Witness", "circuit.signalInput": "Signal Input", - "circuit.compute": "Compute" + "circuit.compute": "Compute", + "circuit.setupExports": "Setup and Exports", + "circuit.provingScheme": "Proving Scheme", + "circuit.ptau": "POWER OF TAU (PTAU)", + "circuit.randomText": "Ceremony: Random Text", + "circuit.randomBeacon": "Ceremony: Random Beacon", + "circuit.exportVerifierContract": "Export verifier contract", + "circuit.exportVerificationKey": "Export verification key", + "circuit.runSetup": "Run setup" }