mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-09 15:31:29 +01:00
Add CLI interface for verifier contract generation (#74)
* add: solidity-verifier workspace member * chore: Update toolchain to 1.74 * feat: Add basic clap cli interface for solidity verifier This includes a cli parser that serves as a way to the user to generate the desired Solidity contracts. * chore: Expose SoldityVerifier template struct * feat: Finish first working version * change: Modify some settings * fix: Fix rebase conflicts * chore: Leave resolver 2 for workspace * chore: Rename KZG+G16 template Now the template refers to Nova + Cyclefold and has a Warning attached to it * fixup * chore: Rename to NovaCyclefoldDecider the template * chore: Change constructors to `new` instead of `from` * add: ProtocolData trait helper This trait helps to treat the serialized data required by the Template as a single element while still allowing a flexible usage. This is specially interesting as allows the cli to operate considering a single path of input data where all the data for the selected protocol co-exists. Reducing the amount of parsing and arguments the user needs to pass to the cli. * chore: Create `From` impls formally Previously we had functions called `from` which had nothing to do with the trait `From`. This addresses this issue and fixes it. Now both `new` and `from` are avaliable. But `from` follows the `From` trait. * add: Support G16, KZG and Nova+Cyclefold in cli This adds a `render` fn for `Protocol` which makes it easier to add new protocols to the CLI as is mainly based in the `ProtocolData` impl behind the scenes of the selected protocol. Aside from that, this commit reworks some minor parts of the CLI config as shorteners for commands or adding `pragma` as an optional parameter. * chore: Adapt `main.rs` to new cli changes As seen, this allows to have a much easier `main.rs` which doesn't have to do any `match` over the selected protocol. * chore: Make solidity helper fns `cfg(test)` * chore: Rework folding-schemes-solidity structure * chore: Remove g1_crs_batch_points_len from KZGData * add: Serde tests for all template targets * tmp: Add NovaCyclefold testing * add: HeaderInclusion template When we use templates that are composed by others (as happens with `NovaCyclefold` one) we sadly see that the License and the `pragma` attributes are rendered once per sub-template. This generic structure solves this issue by being actually the only item rendered which has a sub-template the template we indeed want to render at the end. * chore: Add tests for NovaCyclefold contract This also includes small changes to the lib architecture such as adding constants for GPL3_SDPX_IDENTIFIER or move the default pragma versions used to `mod.rs` * chore: Update g16 to use HeaderInclusion template rendering Now the `ProtocolData` impl falls back to the usage of `HeaderInclusion` it is easier to handle complex templates like `NovaCyclefold`. * add: Small builder-pattern to construct HeaderInclusion Templates As mentioned in previous commits, the idea is that the header is set on an automatic wrapper template applied to the one that we actually want to render. This builder pattern makes it less complex to do such a thing. Specially avoiding unidiomatic `From` implementations. * remove: sdpx & pragma from KZG template Those are externalized and handled by HeaderInclusion template utility * chore: Update templates to use HeaderInclusion builder * chore: Update tests to use HeaderInclusion builderPattern * remove: fixed pragma version in novacyclefold template * chore: Accept Into<Template> in builder * tmp: Only KZG return passes. Fix Groth * fix: Prevent `revert` from paniking for negative tests * feat: Merge G16 and KZG contract results in NovaCyclefold * chore: Add assets for quicker/easier testing Now instead of generating the protocoldata & proofs on each test, we just deserialize * fix: Address clippy & warnings * fix: Spelling to prevent PR farmers LOL * chore: Add about and long_about to CLI tool * add: README.md * chore: Revert asset-based testing approach * remove: Assets folder * fix: Rebase issues * fix: use &mut for Reader * fix: rebase error with Contract name * chore: Reduce tests LOC with setup fn * chore: Set MIT license indentifier for CLI & KZG * chore: Add extra usage example * chore: Update novacyclefold contract comments on soundess * chore: Typo * chore: Allow type complexity clippy for setup fn * chore: Address Pierre's comments * chore: Rename workspace members - folding-schemes-solidity -> soliity-verifiers
This commit is contained in:
169
solidity-verifiers/templates/groth16_verifier.askama.sol
Normal file
169
solidity-verifiers/templates/groth16_verifier.askama.sol
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright 2021 0KIMS association.
|
||||
|
||||
* `solidity-verifiers` added comment
|
||||
This file is a template built out of [snarkJS](https://github.com/iden3/snarkjs) groth16 verifier.
|
||||
See the original ejs template [here](https://github.com/iden3/snarkjs/blob/master/templates/verifier_groth16.sol.ejs)
|
||||
*
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
contract Groth16Verifier {
|
||||
// Scalar field size
|
||||
uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
// Base field size
|
||||
uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
|
||||
// Verification Key data
|
||||
uint256 constant alphax = {{ vkey_alpha_g1.0[0] }};
|
||||
uint256 constant alphay = {{ vkey_alpha_g1.0[1] }};
|
||||
uint256 constant betax1 = {{ vkey_beta_g2.0[0][1] }};
|
||||
uint256 constant betax2 = {{ vkey_beta_g2.0[0][0] }};
|
||||
uint256 constant betay1 = {{ vkey_beta_g2.0[1][1] }};
|
||||
uint256 constant betay2 = {{ vkey_beta_g2.0[1][0] }};
|
||||
uint256 constant gammax1 = {{ vkey_gamma_g2.0[0][1] }};
|
||||
uint256 constant gammax2 = {{ vkey_gamma_g2.0[0][0] }};
|
||||
uint256 constant gammay1 = {{ vkey_gamma_g2.0[1][1] }};
|
||||
uint256 constant gammay2 = {{ vkey_gamma_g2.0[1][0] }};
|
||||
uint256 constant deltax1 = {{ vkey_delta_g2.0[0][1] }};
|
||||
uint256 constant deltax2 = {{ vkey_delta_g2.0[0][0] }};
|
||||
uint256 constant deltay1 = {{ vkey_delta_g2.0[1][1] }};
|
||||
uint256 constant deltay2 = {{ vkey_delta_g2.0[1][0] }};
|
||||
|
||||
{% for (i, point) in gamma_abc_g1.iter().enumerate() %}
|
||||
uint256 constant IC{{i}}x = {{ point.0[0] }};
|
||||
uint256 constant IC{{i}}y = {{ point.0[1] }};
|
||||
{% endfor %}
|
||||
|
||||
// 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[{{ gamma_abc_len - 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 (i, _) in gamma_abc_g1.iter().enumerate() %}
|
||||
{% if loop.first -%}
|
||||
{%- else -%}
|
||||
g1_mulAccC(_pVk, IC{{i}}x, IC{{i}}y, calldataload(add(pubSignals, {{(i-1)*32}})))
|
||||
{%- endif -%}
|
||||
{% endfor %}
|
||||
|
||||
// -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 (i, _) in gamma_abc_g1.iter().enumerate() %}
|
||||
checkField(calldataload(add(_pubSignals, {{i*32}})))
|
||||
{% endfor %}
|
||||
|
||||
// Validate all evaluations
|
||||
let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
|
||||
|
||||
mstore(0, isValid)
|
||||
|
||||
return(0, 0x20)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
solidity-verifiers/templates/header_template.askama.sol
Normal file
4
solidity-verifiers/templates/header_template.askama.sol
Normal file
@@ -0,0 +1,4 @@
|
||||
{{ sdpx }}
|
||||
{{ pragma_version }}
|
||||
|
||||
{{template}}
|
||||
271
solidity-verifiers/templates/kzg10_verifier.askama.sol
Normal file
271
solidity-verifiers/templates/kzg10_verifier.askama.sol
Normal file
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* @author Privacy and Scaling Explorations team - pse.dev
|
||||
* @dev Contains utility functions for ops in BN254; in G_1 mostly.
|
||||
* @notice Forked from https://github.com/weijiekoh/libkzg/tree/master.
|
||||
* Among others, a few of the changes we did on this fork were:
|
||||
* - Templating the pragma version
|
||||
* - Removing type wrappers and use uints instead
|
||||
* - Performing changes on arg types
|
||||
* - Update some of the `require` statements
|
||||
* - Use the bn254 scalar field instead of checking for overflow on the babyjub prime
|
||||
* - In batch checking, we compute auxiliary polynomials and their commitments at the same time.
|
||||
*/
|
||||
contract KZG10Verifier {
|
||||
|
||||
// prime of field F_p over which y^2 = x^3 + 3 is defined
|
||||
uint256 public constant BN254_PRIME_FIELD =
|
||||
21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||
uint256 public constant BN254_SCALAR_FIELD =
|
||||
21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
|
||||
/**
|
||||
* @notice Performs scalar multiplication in G_1.
|
||||
* @param p G_1 point to multiply
|
||||
* @param s Scalar to multiply by
|
||||
* @return r G_1 point p multiplied by scalar s
|
||||
*/
|
||||
function mulScalar(uint256[2] memory p, uint256 s) internal view returns (uint256[2] memory r) {
|
||||
uint256[3] memory input;
|
||||
input[0] = p[0];
|
||||
input[1] = p[1];
|
||||
input[2] = s;
|
||||
bool success;
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40)
|
||||
switch success
|
||||
case 0 { invalid() }
|
||||
}
|
||||
require(success, "bn254: scalar mul failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Negates a point in G_1.
|
||||
* @param p G_1 point to negate
|
||||
* @return uint256[2] G_1 point -p
|
||||
*/
|
||||
function negate(uint256[2] memory p) internal pure returns (uint256[2] memory) {
|
||||
if (p[0] == 0 && p[1] == 0) {
|
||||
return p;
|
||||
}
|
||||
return [p[0], BN254_PRIME_FIELD - (p[1] % BN254_PRIME_FIELD)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Adds two points in G_1.
|
||||
* @param p1 G_1 point 1
|
||||
* @param p2 G_1 point 2
|
||||
* @return r G_1 point p1 + p2
|
||||
*/
|
||||
function add(uint256[2] memory p1, uint256[2] memory p2) internal view returns (uint256[2] memory r) {
|
||||
bool success;
|
||||
uint256[4] memory input = [p1[0], p1[1], p2[0], p2[1]];
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40)
|
||||
switch success
|
||||
case 0 { invalid() }
|
||||
}
|
||||
|
||||
require(success, "bn254: point add failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Computes the pairing check e(p1, p2) * e(p3, p4) == 1
|
||||
* @dev Note that G_2 points a*i + b are encoded as two elements of F_p, (a, b)
|
||||
* @param a_1 G_1 point 1
|
||||
* @param a_2 G_2 point 1
|
||||
* @param b_1 G_1 point 2
|
||||
* @param b_2 G_2 point 2
|
||||
* @return result true if pairing check is successful
|
||||
*/
|
||||
function pairing(uint256[2] memory a_1, uint256[2][2] memory a_2, uint256[2] memory b_1, uint256[2][2] memory b_2)
|
||||
internal
|
||||
view
|
||||
returns (bool result)
|
||||
{
|
||||
uint256[12] memory input = [
|
||||
a_1[0],
|
||||
a_1[1],
|
||||
a_2[0][1], // imaginary part first
|
||||
a_2[0][0],
|
||||
a_2[1][1], // imaginary part first
|
||||
a_2[1][0],
|
||||
b_1[0],
|
||||
b_1[1],
|
||||
b_2[0][1], // imaginary part first
|
||||
b_2[0][0],
|
||||
b_2[1][1], // imaginary part first
|
||||
b_2[1][0]
|
||||
];
|
||||
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, input, 0x180, out, 0x20)
|
||||
switch success
|
||||
case 0 { invalid() }
|
||||
}
|
||||
|
||||
require(success, "bn254: pairing failed");
|
||||
|
||||
return out[0] == 1;
|
||||
}
|
||||
|
||||
uint256[2] G_1 = [
|
||||
{{ g1.0[0] }},
|
||||
{{ g1.0[1] }}
|
||||
];
|
||||
uint256[2][2] G_2 = [
|
||||
[
|
||||
{{ g2.0[0][0] }},
|
||||
{{ g2.0[0][1] }}
|
||||
],
|
||||
[
|
||||
{{ g2.0[1][0] }},
|
||||
{{ g2.0[1][1] }}
|
||||
]
|
||||
];
|
||||
uint256[2][2] VK = [
|
||||
[
|
||||
{{ vk.0[0][0] }},
|
||||
{{ vk.0[0][1] }}
|
||||
],
|
||||
[
|
||||
{{ vk.0[1][0] }},
|
||||
{{ vk.0[1][1] }}
|
||||
]
|
||||
];
|
||||
|
||||
uint256[2][{{ g1_crs_len }}] G1_CRS = [
|
||||
{%- for (i, point) in g1_crs.iter().enumerate() %}
|
||||
[
|
||||
{{ point.0[0] }},
|
||||
{{ point.0[1] }}
|
||||
{% if loop.last -%}
|
||||
]
|
||||
{%- else -%}
|
||||
],
|
||||
{%- endif -%}
|
||||
{% endfor -%}
|
||||
];
|
||||
|
||||
/**
|
||||
* @notice Verifies a single point evaluation proof. Function name follows `ark-poly`.
|
||||
* @dev To avoid ops in G_2, we slightly tweak how the verification is done.
|
||||
* @param c G_1 point commitment to polynomial.
|
||||
* @param pi G_1 point proof.
|
||||
* @param x Value to prove evaluation of polynomial at.
|
||||
* @param y Evaluation poly(x).
|
||||
* @return result Indicates if KZG proof is correct.
|
||||
*/
|
||||
function check(uint256[2] calldata c, uint256[2] calldata pi, uint256 x, uint256 y)
|
||||
public
|
||||
view
|
||||
returns (bool result)
|
||||
{
|
||||
//
|
||||
// we want to:
|
||||
// 1. avoid gas intensive ops in G2
|
||||
// 2. format the pairing check in line with what the evm opcode expects.
|
||||
//
|
||||
// we can do this by tweaking the KZG check to be:
|
||||
//
|
||||
// e(pi, vk - x * g2) = e(c - y * g1, g2) [initial check]
|
||||
// e(pi, vk - x * g2) * e(c - y * g1, g2)^{-1} = 1
|
||||
// e(pi, vk - x * g2) * e(-c + y * g1, g2) = 1 [bilinearity of pairing for all subsequent steps]
|
||||
// e(pi, vk) * e(pi, -x * g2) * e(-c + y * g1, g2) = 1
|
||||
// e(pi, vk) * e(-x * pi, g2) * e(-c + y * g1, g2) = 1
|
||||
// e(pi, vk) * e(x * -pi - c + y * g1, g2) = 1 [done]
|
||||
// |_ rhs_pairing _|
|
||||
//
|
||||
uint256[2] memory rhs_pairing =
|
||||
add(mulScalar(negate(pi), x), add(negate(c), mulScalar(G_1, y)));
|
||||
return pairing(pi, VK, rhs_pairing, G_2);
|
||||
}
|
||||
|
||||
function evalPolyAt(uint256[] memory _coefficients, uint256 _index) public pure returns (uint256) {
|
||||
uint256 m = BN254_SCALAR_FIELD;
|
||||
uint256 result = 0;
|
||||
uint256 powerOfX = 1;
|
||||
|
||||
for (uint256 i = 0; i < _coefficients.length; i++) {
|
||||
uint256 coeff = _coefficients[i];
|
||||
assembly {
|
||||
result := addmod(result, mulmod(powerOfX, coeff, m), m)
|
||||
powerOfX := mulmod(powerOfX, _index, m)
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Ensures that z(x) == 0 and l(x) == y for all x in x_vals and y in y_vals. It returns the commitment to z(x) and l(x).
|
||||
* @param z_coeffs coefficients of the zero polynomial z(x) = (x - x_1)(x - x_2)...(x - x_n).
|
||||
* @param l_coeffs coefficients of the lagrange polynomial l(x).
|
||||
* @param x_vals x values to evaluate the polynomials at.
|
||||
* @param y_vals y values to which l(x) should evaluate to.
|
||||
* @return uint256[2] commitment to z(x).
|
||||
* @return uint256[2] commitment to l(x).
|
||||
*/
|
||||
function checkAndCommitAuxPolys(
|
||||
uint256[] memory z_coeffs,
|
||||
uint256[] memory l_coeffs,
|
||||
uint256[] memory x_vals,
|
||||
uint256[] memory y_vals
|
||||
) public view returns (uint256[2] memory, uint256[2] memory) {
|
||||
// z(x) is of degree len(x_vals), it is a product of linear polynomials (x - x_i)
|
||||
// l(x) is of degree len(x_vals) - 1
|
||||
uint256[2] memory z_commit;
|
||||
uint256[2] memory l_commit;
|
||||
for (uint256 i = 0; i < x_vals.length; i++) {
|
||||
z_commit = add(z_commit, mulScalar(G1_CRS[i], z_coeffs[i])); // update commitment to z(x)
|
||||
l_commit = add(l_commit, mulScalar(G1_CRS[i], l_coeffs[i])); // update commitment to l(x)
|
||||
|
||||
uint256 eval_z = evalPolyAt(z_coeffs, x_vals[i]);
|
||||
uint256 eval_l = evalPolyAt(l_coeffs, x_vals[i]);
|
||||
|
||||
require(eval_z == 0, "checkAndCommitAuxPolys: wrong zero poly");
|
||||
require(eval_l == y_vals[i], "checkAndCommitAuxPolys: wrong lagrange poly");
|
||||
}
|
||||
// z(x) has len(x_vals) + 1 coeffs, we add to the commitment the last coeff of z(x)
|
||||
z_commit = add(z_commit, mulScalar(G1_CRS[z_coeffs.length - 1], z_coeffs[z_coeffs.length - 1]));
|
||||
|
||||
return (z_commit, l_commit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Verifies a batch of point evaluation proofs. Function name follows `ark-poly`.
|
||||
* @dev To avoid ops in G_2, we slightly tweak how the verification is done.
|
||||
* @param c G1 point commitment to polynomial.
|
||||
* @param pi G2 point proof.
|
||||
* @param x_vals Values to prove evaluation of polynomial at.
|
||||
* @param y_vals Evaluation poly(x).
|
||||
* @param l_coeffs Coefficients of the lagrange polynomial.
|
||||
* @param z_coeffs Coefficients of the zero polynomial z(x) = (x - x_1)(x - x_2)...(x - x_n).
|
||||
* @return result Indicates if KZG proof is correct.
|
||||
*/
|
||||
function batchCheck(
|
||||
uint256[2] calldata c,
|
||||
uint256[2][2] calldata pi,
|
||||
uint256[] calldata x_vals,
|
||||
uint256[] calldata y_vals,
|
||||
uint256[] calldata l_coeffs,
|
||||
uint256[] calldata z_coeffs
|
||||
) public view returns (bool result) {
|
||||
//
|
||||
// we want to:
|
||||
// 1. avoid gas intensive ops in G2
|
||||
// 2. format the pairing check in line with what the evm opcode expects.
|
||||
//
|
||||
// we can do this by tweaking the KZG check to be:
|
||||
//
|
||||
// e(z(r) * g1, pi) * e(g1, l(r) * g2) = e(c, g2) [initial check]
|
||||
// e(z(r) * g1, pi) * e(l(r) * g1, g2) * e(c, g2)^{-1} = 1 [bilinearity of pairing]
|
||||
// e(z(r) * g1, pi) * e(l(r) * g1 - c, g2) = 1 [done]
|
||||
//
|
||||
(uint256[2] memory z_commit, uint256[2] memory l_commit) =
|
||||
checkAndCommitAuxPolys(z_coeffs, l_coeffs, x_vals, y_vals);
|
||||
uint256[2] memory neg_commit = negate(c);
|
||||
return pairing(z_commit, pi, add(l_commit, neg_commit), G_2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{{ groth16_verifier }}
|
||||
|
||||
{{ kzg10_verifier }}
|
||||
|
||||
/**
|
||||
* @author PSE & 0xPARC
|
||||
* @title NovaDecider contract, for verifying zk-snarks Nova IVC proofs.
|
||||
* @dev This is an askama template. It will feature a snarkjs groth16 and a kzg10 verifier, from which this contract inherits.
|
||||
* WARNING: This contract is not complete nor finished. It lacks checks to ensure that no soundness issues can happen.
|
||||
* Indeed, we know some of the checks that are missing. And we're working on the solution
|
||||
* but for now, it's good enough for testing and benchmarking.
|
||||
*/
|
||||
contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
||||
function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[1] calldata _pubSignals, uint256[2] calldata c, uint256[2] calldata pi, uint256 x, uint256 y) public view returns (bool) {
|
||||
bool success_kzg = super.check(c, pi, x, y);
|
||||
require(success_kzg == true, "KZG Failed");
|
||||
|
||||
// for now, we do not relate the Groth16 and KZG10 proofs
|
||||
bool success_g16 = super.verifyProof(_pA, _pB, _pC, _pubSignals);
|
||||
require(success_g16 == true, "G16 Failed");
|
||||
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user