mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-15 18:31:30 +01:00
* Add solidity verifier of the nova+cyclefold, and add method to prepare the calldata from Decider's proof. Missing conversion of the point coordinates into limbs (ark compatible) * chore: adding comments linking to the contract's signature * chore: update .gitignore * chore: add num-bigint as dev dependency * fix: work with abs path for storing generated sol code * chore: update comment * feat: solidity verifier working on single and multi-input circuits * feat: multi-input folding verification working + fixing encoding of additive identity in calldata * chore: make bigint a dependency * refactor: import utils functions from utils.rs and make them available from anywhere * chore: make utils and evm available publicly * fix: pub mod instead * chore: make relevant method public and add `get_decider_template_for_cyclefold_decider` to exported objects * solidity-verifiers: move tests to their corresponding files * small update: Cyclefold -> CycleFold at the missing places * abstract nova-cyclefold solidity verifiers tests to avoid code duplication, and abstract also the computed setup params (FS & Decider) to compute them only once for all related tests to save test time * small polish after rebase to last main branch changes * rm unneeded Option for KZGData::g1_crs_batch_points * add checks modifying z_0 & z_i to nova_cyclefold_solidity_verifier test * add light-test feature to decider_eth_circuit to use it in solidity-verifier tests without the big circuit * solidity-verifiers: groth16 template: port the fix from https://github.com/iden3/snarkjs/pull/480 & https://github.com/iden3/snarkjs/issues/479 * add print warning msg for light-test in DeciderEthCircuit * solidity-verifiers: update limbs logic to nonnative last version, parametrize limbs params solidity-verifiers: * update solidity limbs logic to last nonnative impl version, and to last u_i.x impl * parametrize limbs params * add light-test feature: replace the '#[cfg(not(test))]' by the 'light-test' feature that by default is not enabled, so when running the github actions we enable the feature 'light-tests', and then we can have a full-test that runs the test without the 'light-tests' flag, but we don't run this big test every time. The choice of a feature is to allow us to control this from other-crates tests (for example for the solidity-verifier separated crate tests, to avoid running the full heavy circuit in the solidity tests) * move solidity constants into template constants for auto compute of params * polishing * revm use only needed feature This is to avoid c depencency for c-kzg which is behind the c-kzg flag and not needed. * nova_cyclefold_decider.sol header * rearrange test helpers position, add error for min number of steps * in solidity-verifiers: 'data'->'vk/verifier key' * add From for NovaCycleFoldVerifierKey from original vks to simplify dev flow, also conditionally template the batchCheck related structs and methods from the KZG10 solidity template --------- Co-authored-by: dmpierre <pdaixmoreux@gmail.com>
170 lines
6.4 KiB
Solidity
170 lines
6.4 KiB
Solidity
/*
|
|
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, r)) {
|
|
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)
|
|
}
|
|
}
|
|
}
|