github.com/consensys/gnark@v0.11.0/backend/plonk/bn254/solidity.go (about) 1 package plonk 2 3 const tmplSolidityVerifier = `// SPDX-License-Identifier: Apache-2.0 4 5 // Copyright 2023 Consensys Software Inc. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 // See the License for the specific language governing permissions and 17 // limitations under the License. 18 19 // Code generated by gnark DO NOT EDIT 20 21 pragma solidity {{ .Cfg.PragmaVersion }}; 22 23 contract PlonkVerifier { 24 25 uint256 private constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; 26 uint256 private constant R_MOD_MINUS_ONE = 21888242871839275222246405745257275088548364400416034343698204186575808495616; 27 uint256 private constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583; 28 {{ range $index, $element := .Vk.Kzg.G2 }} 29 uint256 private constant G2_SRS_{{ $index }}_X_0 = {{ (fpstr $element.X.A1) }}; 30 uint256 private constant G2_SRS_{{ $index }}_X_1 = {{ (fpstr $element.X.A0) }}; 31 uint256 private constant G2_SRS_{{ $index }}_Y_0 = {{ (fpstr $element.Y.A1) }}; 32 uint256 private constant G2_SRS_{{ $index }}_Y_1 = {{ (fpstr $element.Y.A0) }}; 33 {{ end }} 34 uint256 private constant G1_SRS_X = {{ fpstr .Vk.Kzg.G1.X }}; 35 uint256 private constant G1_SRS_Y = {{ fpstr .Vk.Kzg.G1.Y }}; 36 37 // ----------------------- vk --------------------- 38 uint256 private constant VK_NB_PUBLIC_INPUTS = {{ .Vk.NbPublicVariables }}; 39 uint256 private constant VK_DOMAIN_SIZE = {{ .Vk.Size }}; 40 uint256 private constant VK_INV_DOMAIN_SIZE = {{ (frstr .Vk.SizeInv) }}; 41 uint256 private constant VK_OMEGA = {{ (frstr .Vk.Generator) }}; 42 uint256 private constant VK_QL_COM_X = {{ (fpstr .Vk.Ql.X) }}; 43 uint256 private constant VK_QL_COM_Y = {{ (fpstr .Vk.Ql.Y) }}; 44 uint256 private constant VK_QR_COM_X = {{ (fpstr .Vk.Qr.X) }}; 45 uint256 private constant VK_QR_COM_Y = {{ (fpstr .Vk.Qr.Y) }}; 46 uint256 private constant VK_QM_COM_X = {{ (fpstr .Vk.Qm.X) }}; 47 uint256 private constant VK_QM_COM_Y = {{ (fpstr .Vk.Qm.Y) }}; 48 uint256 private constant VK_QO_COM_X = {{ (fpstr .Vk.Qo.X) }}; 49 uint256 private constant VK_QO_COM_Y = {{ (fpstr .Vk.Qo.Y) }}; 50 uint256 private constant VK_QK_COM_X = {{ (fpstr .Vk.Qk.X) }}; 51 uint256 private constant VK_QK_COM_Y = {{ (fpstr .Vk.Qk.Y) }}; 52 {{ range $index, $element := .Vk.S }} 53 uint256 private constant VK_S{{ inc $index }}_COM_X = {{ (fpstr $element.X) }}; 54 uint256 private constant VK_S{{ inc $index }}_COM_Y = {{ (fpstr $element.Y) }}; 55 {{ end }} 56 uint256 private constant VK_COSET_SHIFT = {{ frstr .Vk.CosetShift }}; 57 58 {{ range $index, $element := .Vk.Qcp}} 59 uint256 private constant VK_QCP_{{ $index }}_X = {{ (fpstr $element.X) }}; 60 uint256 private constant VK_QCP_{{ $index }}_Y = {{ (fpstr $element.Y) }}; 61 {{ end }} 62 63 {{ range $index, $element := .Vk.CommitmentConstraintIndexes -}} 64 uint256 private constant VK_INDEX_COMMIT_API_{{ $index }} = {{ $element }}; 65 {{ end -}} 66 uint256 private constant VK_NB_CUSTOM_GATES = {{ len .Vk.CommitmentConstraintIndexes }}; 67 68 // ------------------------------------------------ 69 70 // size of the proof without call custom gate 71 uint256 private constant FIXED_PROOF_SIZE = 0x300; 72 73 // offset proof 74 {{ $offset := 0 }} 75 uint256 private constant PROOF_L_COM_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 76 uint256 private constant PROOF_L_COM_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 77 uint256 private constant PROOF_R_COM_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 78 uint256 private constant PROOF_R_COM_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 79 uint256 private constant PROOF_O_COM_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 80 uint256 private constant PROOF_O_COM_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 81 82 // h = h_0 + x^{n+2}h_1 + x^{2(n+2)}h_2 83 uint256 private constant PROOF_H_0_COM_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 84 uint256 private constant PROOF_H_0_COM_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 85 uint256 private constant PROOF_H_1_COM_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 86 uint256 private constant PROOF_H_1_COM_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 87 uint256 private constant PROOF_H_2_COM_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 88 uint256 private constant PROOF_H_2_COM_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 89 90 // "evaluations of wire polynomials at zeta 91 uint256 private constant PROOF_L_AT_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 92 uint256 private constant PROOF_R_AT_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 93 uint256 private constant PROOF_O_AT_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 94 95 // S1(zeta),S2(zeta) 96 uint256 private constant PROOF_S1_AT_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} // Sσ1(zeta) 97 uint256 private constant PROOF_S2_AT_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} // Sσ2(zeta) 98 99 // [Z] 100 uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 101 uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 102 103 uint256 private constant PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA = {{ hex $offset }};{{ $offset = add $offset 0x20}} // z(w*zeta) 104 105 // Folded proof for the opening of linearised poly, l, r, o, s_1, s_2, qcp 106 uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 107 uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 108 109 uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 110 uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 111 112 uint256 private constant PROOF_OPENING_QCP_AT_ZETA = {{ hex $offset }}; 113 uint256 private constant PROOF_BSB_COMMITMENTS = {{ hex (add $offset (mul (len .Vk.CommitmentConstraintIndexes) 32 ) )}}; 114 115 // -------- offset state 116 117 // challenges to check the claimed quotient 118 {{ $offset = 0 }} 119 uint256 private constant STATE_ALPHA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 120 uint256 private constant STATE_BETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 121 uint256 private constant STATE_GAMMA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 122 uint256 private constant STATE_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 123 uint256 private constant STATE_ALPHA_SQUARE_LAGRANGE_0 = {{ hex $offset }};{{ $offset = add $offset 0x20}} 124 uint256 private constant STATE_FOLDED_H_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 125 uint256 private constant STATE_FOLDED_H_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 126 uint256 private constant STATE_LINEARISED_POLYNOMIAL_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} 127 uint256 private constant STATE_LINEARISED_POLYNOMIAL_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 128 uint256 private constant STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA = {{ hex $offset }};{{ $offset = add $offset 0x20}} 129 uint256 private constant STATE_FOLDED_CLAIMED_VALUES = {{ hex $offset }};{{ $offset = add $offset 0x20}} // Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp 130 uint256 private constant STATE_FOLDED_DIGESTS_X = {{ hex $offset }};{{ $offset = add $offset 0x20}} // linearised poly, l, r, o, s_1, s_2, qcp 131 uint256 private constant STATE_FOLDED_DIGESTS_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} 132 uint256 private constant STATE_PI = {{ hex $offset }};{{ $offset = add $offset 0x20}} 133 uint256 private constant STATE_ZETA_POWER_N_MINUS_ONE = {{ hex $offset }};{{ $offset = add $offset 0x20}} 134 uint256 private constant STATE_GAMMA_KZG = {{ hex $offset }};{{ $offset = add $offset 0x20}} 135 uint256 private constant STATE_SUCCESS = {{ hex $offset }};{{ $offset = add $offset 0x20}} 136 uint256 private constant STATE_CHECK_VAR = {{ hex $offset }};{{ $offset = add $offset 0x20}} // /!\ this slot is used for debugging only 137 uint256 private constant STATE_LAST_MEM = {{ hex $offset }};{{ $offset = add $offset 0x20}} 138 139 // -------- utils (for Fiat Shamir) 140 uint256 private constant FS_ALPHA = 0x616C706861; // "alpha" 141 uint256 private constant FS_BETA = 0x62657461; // "beta" 142 uint256 private constant FS_GAMMA = 0x67616d6d61; // "gamma" 143 uint256 private constant FS_ZETA = 0x7a657461; // "zeta" 144 uint256 private constant FS_GAMMA_KZG = 0x67616d6d61; // "gamma" 145 146 // -------- errors 147 uint256 private constant ERROR_STRING_ID = 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string) 148 149 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} 150 // -------- utils (for hash_fr) 151 uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 152 uint256 private constant HASH_FR_ZERO_UINT256 = 0; 153 uint8 private constant HASH_FR_LEN_IN_BYTES = 48; 154 uint8 private constant HASH_FR_SIZE_DOMAIN = 11; 155 uint8 private constant HASH_FR_ONE = 1; 156 uint8 private constant HASH_FR_TWO = 2; 157 {{ end }} 158 159 // -------- precompiles 160 uint8 private constant SHA2 = 0x2; 161 uint8 private constant MOD_EXP = 0x5; 162 uint8 private constant EC_ADD = 0x6; 163 uint8 private constant EC_MUL = 0x7; 164 uint8 private constant EC_PAIR = 0x8; 165 166 /// Verify a Plonk proof. 167 /// Reverts if the proof or the public inputs are malformed. 168 /// @param proof serialised plonk proof (using gnark's MarshalSolidity) 169 /// @param public_inputs (must be reduced) 170 /// @return success true if the proof passes false otherwise 171 function Verify(bytes calldata proof, uint256[] calldata public_inputs) 172 public view returns(bool success) { 173 174 assembly { 175 176 let mem := mload(0x40) 177 let freeMem := add(mem, STATE_LAST_MEM) 178 179 // sanity checks 180 check_number_of_public_inputs(public_inputs.length) 181 check_inputs_size(public_inputs.length, public_inputs.offset) 182 check_proof_size(proof.length) 183 check_proof_openings_size(proof.offset) 184 185 // compute the challenges 186 let prev_challenge_non_reduced 187 prev_challenge_non_reduced := derive_gamma(proof.offset, public_inputs.length, public_inputs.offset) 188 prev_challenge_non_reduced := derive_beta(prev_challenge_non_reduced) 189 prev_challenge_non_reduced := derive_alpha(proof.offset, prev_challenge_non_reduced) 190 derive_zeta(proof.offset, prev_challenge_non_reduced) 191 192 // evaluation of Z=Xⁿ-1 at ζ, we save this value 193 let zeta := mload(add(mem, STATE_ZETA)) 194 let zeta_power_n_minus_one := addmod(pow(zeta, VK_DOMAIN_SIZE, freeMem), sub(R_MOD, 1), R_MOD) 195 mstore(add(mem, STATE_ZETA_POWER_N_MINUS_ONE), zeta_power_n_minus_one) 196 197 // public inputs contribution 198 let l_pi := sum_pi_wo_api_commit(public_inputs.offset, public_inputs.length, freeMem) 199 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 ) -}} 200 let l_pi_commit := sum_pi_commit(proof.offset, public_inputs.length, freeMem) 201 l_pi := addmod(l_pi_commit, l_pi, R_MOD) 202 {{ end -}} 203 mstore(add(mem, STATE_PI), l_pi) 204 205 compute_alpha_square_lagrange_0() 206 compute_opening_linearised_polynomial(proof.offset) 207 fold_h(proof.offset) 208 compute_commitment_linearised_polynomial(proof.offset) 209 compute_gamma_kzg(proof.offset) 210 fold_state(proof.offset) 211 batch_verify_multi_points(proof.offset) 212 213 success := mload(add(mem, STATE_SUCCESS)) 214 215 // Beginning errors ------------------------------------------------- 216 217 function error_nb_public_inputs() { 218 let ptError := mload(0x40) 219 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 220 mstore(add(ptError, 0x4), 0x20) 221 mstore(add(ptError, 0x24), 0x1d) 222 mstore(add(ptError, 0x44), "wrong number of public inputs") 223 revert(ptError, 0x64) 224 } 225 226 /// Called when an exponentiation mod r fails 227 function error_mod_exp() { 228 let ptError := mload(0x40) 229 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 230 mstore(add(ptError, 0x4), 0x20) 231 mstore(add(ptError, 0x24), 0xc) 232 mstore(add(ptError, 0x44), "error mod exp") 233 revert(ptError, 0x64) 234 } 235 236 /// Called when an operation on Bn254 fails 237 /// @dev for instance when calling EcMul on a point not on Bn254. 238 function error_ec_op() { 239 let ptError := mload(0x40) 240 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 241 mstore(add(ptError, 0x4), 0x20) 242 mstore(add(ptError, 0x24), 0x12) 243 mstore(add(ptError, 0x44), "error ec operation") 244 revert(ptError, 0x64) 245 } 246 247 /// Called when one of the public inputs is not reduced. 248 function error_inputs_size() { 249 let ptError := mload(0x40) 250 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 251 mstore(add(ptError, 0x4), 0x20) 252 mstore(add(ptError, 0x24), 0x18) 253 mstore(add(ptError, 0x44), "inputs are bigger than r") 254 revert(ptError, 0x64) 255 } 256 257 /// Called when the size proof is not as expected 258 /// @dev to avoid overflow attack for instance 259 function error_proof_size() { 260 let ptError := mload(0x40) 261 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 262 mstore(add(ptError, 0x4), 0x20) 263 mstore(add(ptError, 0x24), 0x10) 264 mstore(add(ptError, 0x44), "wrong proof size") 265 revert(ptError, 0x64) 266 } 267 268 /// Called when one the openings is bigger than r 269 /// The openings are the claimed evalutions of a polynomial 270 /// in a Kzg proof. 271 function error_proof_openings_size() { 272 let ptError := mload(0x40) 273 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 274 mstore(add(ptError, 0x4), 0x20) 275 mstore(add(ptError, 0x24), 0x16) 276 mstore(add(ptError, 0x44), "openings bigger than r") 277 revert(ptError, 0x64) 278 } 279 280 function error_pairing() { 281 let ptError := mload(0x40) 282 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 283 mstore(add(ptError, 0x4), 0x20) 284 mstore(add(ptError, 0x24), 0xd) 285 mstore(add(ptError, 0x44), "error pairing") 286 revert(ptError, 0x64) 287 } 288 289 function error_verify() { 290 let ptError := mload(0x40) 291 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 292 mstore(add(ptError, 0x4), 0x20) 293 mstore(add(ptError, 0x24), 0xc) 294 mstore(add(ptError, 0x44), "error verify") 295 revert(ptError, 0x64) 296 } 297 298 function error_random_generation() { 299 let ptError := mload(0x40) 300 mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) 301 mstore(add(ptError, 0x4), 0x20) 302 mstore(add(ptError, 0x24), 0x14) 303 mstore(add(ptError, 0x44), "error random gen kzg") 304 revert(ptError, 0x64) 305 } 306 // end errors ------------------------------------------------- 307 308 // Beginning checks ------------------------------------------------- 309 310 /// @param s actual number of public inputs 311 function check_number_of_public_inputs(s) { 312 if iszero(eq(s, VK_NB_PUBLIC_INPUTS)) { 313 error_nb_public_inputs() 314 } 315 } 316 317 /// Checks that the public inputs are < R_MOD. 318 /// @param s number of public inputs 319 /// @param p pointer to the public inputs array 320 function check_inputs_size(s, p) { 321 for {let i} lt(i, s) {i:=add(i,1)} 322 { 323 if gt(calldataload(p), R_MOD_MINUS_ONE) { 324 error_inputs_size() 325 } 326 p := add(p, 0x20) 327 } 328 } 329 330 /// Checks if the proof is of the correct size 331 /// @param actual_proof_size size of the proof (not the expected size) 332 function check_proof_size(actual_proof_size) { 333 let expected_proof_size := add(FIXED_PROOF_SIZE, mul(VK_NB_CUSTOM_GATES,0x60)) 334 if iszero(eq(actual_proof_size, expected_proof_size)) { 335 error_proof_size() 336 } 337 } 338 339 /// Checks if the multiple openings of the polynomials are < R_MOD. 340 /// @param aproof pointer to the beginning of the proof 341 /// @dev the 'a' prepending proof is to have a local name 342 function check_proof_openings_size(aproof) { 343 344 // PROOF_L_AT_ZETA 345 let p := add(aproof, PROOF_L_AT_ZETA) 346 if gt(calldataload(p), R_MOD_MINUS_ONE) { 347 error_proof_openings_size() 348 } 349 350 // PROOF_R_AT_ZETA 351 p := add(aproof, PROOF_R_AT_ZETA) 352 if gt(calldataload(p), R_MOD_MINUS_ONE) { 353 error_proof_openings_size() 354 } 355 356 // PROOF_O_AT_ZETA 357 p := add(aproof, PROOF_O_AT_ZETA) 358 if gt(calldataload(p), R_MOD_MINUS_ONE) { 359 error_proof_openings_size() 360 } 361 362 // PROOF_S1_AT_ZETA 363 p := add(aproof, PROOF_S1_AT_ZETA) 364 if gt(calldataload(p), R_MOD_MINUS_ONE) { 365 error_proof_openings_size() 366 } 367 368 // PROOF_S2_AT_ZETA 369 p := add(aproof, PROOF_S2_AT_ZETA) 370 if gt(calldataload(p), R_MOD_MINUS_ONE) { 371 error_proof_openings_size() 372 } 373 374 // PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA 375 p := add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA) 376 if gt(calldataload(p), R_MOD_MINUS_ONE) { 377 error_proof_openings_size() 378 } 379 380 // PROOF_OPENING_QCP_AT_ZETA 381 382 p := add(aproof, PROOF_OPENING_QCP_AT_ZETA) 383 for {let i:=0} lt(i, VK_NB_CUSTOM_GATES) {i:=add(i,1)} 384 { 385 if gt(calldataload(p), R_MOD_MINUS_ONE) { 386 error_proof_openings_size() 387 } 388 p := add(p, 0x20) 389 } 390 391 } 392 // end checks ------------------------------------------------- 393 394 // Beginning challenges ------------------------------------------------- 395 396 /// Derive gamma as Sha256(<transcript>) 397 /// @param aproof pointer to the proof 398 /// @param nb_pi number of public inputs 399 /// @param pi pointer to the array of public inputs 400 /// @return the challenge gamma, not reduced 401 /// @notice The transcript is the concatenation (in this order) of: 402 /// * the word "gamma" in ascii, equal to [0x67,0x61,0x6d, 0x6d, 0x61] and encoded as a uint256. 403 /// * the commitments to the permutation polynomials S1, S2, S3, where we concatenate the coordinates of those points 404 /// * the commitments of Ql, Qr, Qm, Qo, Qk 405 /// * the public inputs 406 /// * the commitments of the wires related to the custom gates (commitments_wires_commit_api) 407 /// * commitments to L, R, O (proof_<l,r,o>_com_<x,y>) 408 /// The data described above is written starting at mPtr. "gamma" lies on 5 bytes, 409 /// and is encoded as a uint256 number n. In basis b = 256, the number looks like this 410 /// [0 0 0 .. 0x67 0x61 0x6d, 0x6d, 0x61]. The first non zero entry is at position 27=0x1b 411 /// Gamma reduced (the actual challenge) is stored at add(state, state_gamma) 412 function derive_gamma(aproof, nb_pi, pi)->gamma_not_reduced { 413 414 let state := mload(0x40) 415 let mPtr := add(state, STATE_LAST_MEM) 416 417 mstore(mPtr, FS_GAMMA) // "gamma" 418 419 {{ $offset = 0x20 }} 420 mstore(add(mPtr, {{ hex $offset }}), VK_S1_COM_X) {{ $offset = add $offset 0x20}} 421 mstore(add(mPtr, {{ hex $offset }}), VK_S1_COM_Y) {{ $offset = add $offset 0x20}} 422 mstore(add(mPtr, {{ hex $offset }}), VK_S2_COM_X) {{ $offset = add $offset 0x20}} 423 mstore(add(mPtr, {{ hex $offset }}), VK_S2_COM_Y) {{ $offset = add $offset 0x20}} 424 mstore(add(mPtr, {{ hex $offset }}), VK_S3_COM_X) {{ $offset = add $offset 0x20}} 425 mstore(add(mPtr, {{ hex $offset }}), VK_S3_COM_Y) {{ $offset = add $offset 0x20}} 426 mstore(add(mPtr, {{ hex $offset }}), VK_QL_COM_X) {{ $offset = add $offset 0x20}} 427 mstore(add(mPtr, {{ hex $offset }}), VK_QL_COM_Y) {{ $offset = add $offset 0x20}} 428 mstore(add(mPtr, {{ hex $offset }}), VK_QR_COM_X) {{ $offset = add $offset 0x20}} 429 mstore(add(mPtr, {{ hex $offset }}), VK_QR_COM_Y) {{ $offset = add $offset 0x20}} 430 mstore(add(mPtr, {{ hex $offset }}), VK_QM_COM_X) {{ $offset = add $offset 0x20}} 431 mstore(add(mPtr, {{ hex $offset }}), VK_QM_COM_Y) {{ $offset = add $offset 0x20}} 432 mstore(add(mPtr, {{ hex $offset }}), VK_QO_COM_X) {{ $offset = add $offset 0x20}} 433 mstore(add(mPtr, {{ hex $offset }}), VK_QO_COM_Y) {{ $offset = add $offset 0x20}} 434 mstore(add(mPtr, {{ hex $offset }}), VK_QK_COM_X) {{ $offset = add $offset 0x20}} 435 mstore(add(mPtr, {{ hex $offset }}), VK_QK_COM_Y) {{ $offset = add $offset 0x20}} 436 {{ range $index, $element := .Vk.CommitmentConstraintIndexes}} 437 mstore(add(mPtr, {{ hex $offset }}), VK_QCP_{{ $index }}_X) {{ $offset = add $offset 0x20}} 438 mstore(add(mPtr, {{ hex $offset }}), VK_QCP_{{ $index }}_Y) {{ $offset = add $offset 0x20}} 439 {{ end }} 440 // public inputs 441 let _mPtr := add(mPtr, {{ hex (add (mul (len .Vk.CommitmentConstraintIndexes) 64) 544) }}) 442 let size_pi_in_bytes := mul(nb_pi, 0x20) 443 calldatacopy(_mPtr, pi, size_pi_in_bytes) 444 _mPtr := add(_mPtr, size_pi_in_bytes) 445 446 // commitments to l, r, o 447 let size_commitments_lro_in_bytes := 0xc0 448 calldatacopy(_mPtr, aproof, size_commitments_lro_in_bytes) 449 _mPtr := add(_mPtr, size_commitments_lro_in_bytes) 450 451 // total size is : 452 // sizegamma(=0x5) + 11*64(=0x2c0) 453 // + nb_public_inputs*0x20 454 // + nb_custom gates*0x40 455 let size := add(0x2c5, size_pi_in_bytes) 456 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} 457 size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40)) 458 {{ end -}} 459 let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma" 460 if iszero(l_success) { 461 error_verify() 462 } 463 gamma_not_reduced := mload(mPtr) 464 mstore(add(state, STATE_GAMMA), mod(gamma_not_reduced, R_MOD)) 465 } 466 467 /// derive beta as Sha256<transcript> 468 /// @param gamma_not_reduced the previous challenge (gamma) not reduced 469 /// @return beta_not_reduced the next challenge, beta, not reduced 470 /// @notice the transcript consists of the previous challenge only. 471 /// The reduced version of beta is stored at add(state, state_beta) 472 function derive_beta(gamma_not_reduced)->beta_not_reduced{ 473 474 let state := mload(0x40) 475 let mPtr := add(mload(0x40), STATE_LAST_MEM) 476 477 // beta 478 mstore(mPtr, FS_BETA) // "beta" 479 mstore(add(mPtr, 0x20), gamma_not_reduced) 480 let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1c), 0x24, mPtr, 0x20) //0x1b -> 000.."gamma" 481 if iszero(l_success) { 482 error_verify() 483 } 484 beta_not_reduced := mload(mPtr) 485 mstore(add(state, STATE_BETA), mod(beta_not_reduced, R_MOD)) 486 } 487 488 /// derive alpha as sha256<transcript> 489 /// @param aproof pointer to the proof object 490 /// @param beta_not_reduced the previous challenge (beta) not reduced 491 /// @return alpha_not_reduced the next challenge, alpha, not reduced 492 /// @notice the transcript consists of the previous challenge (beta) 493 /// not reduced, the commitments to the wires associated to the QCP_i, 494 /// and the commitment to the grand product polynomial 495 function derive_alpha(aproof, beta_not_reduced)->alpha_not_reduced { 496 497 let state := mload(0x40) 498 let mPtr := add(mload(0x40), STATE_LAST_MEM) 499 let full_size := 0x65 // size("alpha") + 0x20 (previous challenge) 500 501 // alpha 502 mstore(mPtr, FS_ALPHA) // "alpha" 503 let _mPtr := add(mPtr, 0x20) 504 mstore(_mPtr, beta_not_reduced) 505 _mPtr := add(_mPtr, 0x20) 506 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} 507 // Bsb22Commitments 508 let proof_bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) 509 let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES) 510 calldatacopy(_mPtr, proof_bsb_commitments, size_bsb_commitments) 511 _mPtr := add(_mPtr, size_bsb_commitments) 512 full_size := add(full_size, size_bsb_commitments) 513 {{ end }} 514 // [Z], the commitment to the grand product polynomial 515 calldatacopy(_mPtr, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), 0x40) 516 let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1b), full_size, mPtr, 0x20) 517 if iszero(l_success) { 518 error_verify() 519 } 520 521 alpha_not_reduced := mload(mPtr) 522 mstore(add(state, STATE_ALPHA), mod(alpha_not_reduced, R_MOD)) 523 } 524 525 /// derive zeta as sha256<transcript> 526 /// @param aproof pointer to the proof object 527 /// @param alpha_not_reduced the previous challenge (alpha) not reduced 528 /// The transcript consists of the previous challenge and the commitment to 529 /// the quotient polynomial h. 530 function derive_zeta(aproof, alpha_not_reduced) { 531 532 let state := mload(0x40) 533 let mPtr := add(mload(0x40), STATE_LAST_MEM) 534 535 // zeta 536 mstore(mPtr, FS_ZETA) // "zeta" 537 mstore(add(mPtr, 0x20), alpha_not_reduced) 538 calldatacopy(add(mPtr, 0x40), add(aproof, PROOF_H_0_COM_X), 0xc0) 539 let l_success := staticcall(gas(), SHA2, add(mPtr, 0x1c), 0xe4, mPtr, 0x20) 540 if iszero(l_success) { 541 error_verify() 542 } 543 let zeta_not_reduced := mload(mPtr) 544 mstore(add(state, STATE_ZETA), mod(zeta_not_reduced, R_MOD)) 545 } 546 // END challenges ------------------------------------------------- 547 548 // BEGINNING compute_pi ------------------------------------------------- 549 550 /// sum_pi_wo_api_commit computes the public inputs contributions, 551 /// except for the public inputs coming from the custom gate 552 /// @param ins pointer to the public inputs 553 /// @param n number of public inputs 554 /// @param mPtr free memory 555 /// @return pi_wo_commit public inputs contribution (except the public inputs coming from the custom gate) 556 function sum_pi_wo_api_commit(ins, n, mPtr)->pi_wo_commit { 557 558 let state := mload(0x40) 559 let z := mload(add(state, STATE_ZETA)) 560 let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) 561 562 let li := mPtr 563 batch_compute_lagranges_at_z(z, zpnmo, n, li) 564 565 let tmp := 0 566 for {let i:=0} lt(i,n) {i:=add(i,1)} 567 { 568 tmp := mulmod(mload(li), calldataload(ins), R_MOD) 569 pi_wo_commit := addmod(pi_wo_commit, tmp, R_MOD) 570 li := add(li, 0x20) 571 ins := add(ins, 0x20) 572 } 573 574 } 575 576 /// batch_compute_lagranges_at_z computes [L_0(z), .., L_{n-1}(z)] 577 /// @param z point at which the Lagranges are evaluated 578 /// @param zpnmo ζⁿ-1 579 /// @param n_pub number of public inputs (number of Lagranges to compute) 580 /// @param mPtr pointer to which the results are stored 581 function batch_compute_lagranges_at_z(z, zpnmo, n_pub, mPtr) { 582 583 let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1) 584 585 let _w := 1 586 let _mPtr := mPtr 587 for {let i:=0} lt(i,n_pub) {i:=add(i,1)} 588 { 589 mstore(_mPtr, addmod(z,sub(R_MOD, _w), R_MOD)) 590 _w := mulmod(_w, VK_OMEGA, R_MOD) 591 _mPtr := add(_mPtr, 0x20) 592 } 593 batch_invert(mPtr, n_pub, _mPtr) 594 _mPtr := mPtr 595 _w := 1 596 for {let i:=0} lt(i,n_pub) {i:=add(i,1)} 597 { 598 mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn , R_MOD), _w, R_MOD)) 599 _mPtr := add(_mPtr, 0x20) 600 _w := mulmod(_w, VK_OMEGA, R_MOD) 601 } 602 } 603 604 /// @notice Montgomery trick for batch inversion mod R_MOD 605 /// @param ins pointer to the data to batch invert 606 /// @param number of elements to batch invert 607 /// @param mPtr free memory 608 function batch_invert(ins, nb_ins, mPtr) { 609 mstore(mPtr, 1) 610 let offset := 0 611 for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} 612 { 613 let prev := mload(add(mPtr, offset)) 614 let cur := mload(add(ins, offset)) 615 cur := mulmod(prev, cur, R_MOD) 616 offset := add(offset, 0x20) 617 mstore(add(mPtr, offset), cur) 618 } 619 ins := add(ins, sub(offset, 0x20)) 620 mPtr := add(mPtr, offset) 621 let inv := pow(mload(mPtr), sub(R_MOD,2), add(mPtr, 0x20)) 622 for {let i:=0} lt(i, nb_ins) {i:=add(i,1)} 623 { 624 mPtr := sub(mPtr, 0x20) 625 let tmp := mload(ins) 626 let cur := mulmod(inv, mload(mPtr), R_MOD) 627 mstore(ins, cur) 628 inv := mulmod(inv, tmp, R_MOD) 629 ins := sub(ins, 0x20) 630 } 631 } 632 633 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} 634 /// Public inputs (the ones coming from the custom gate) contribution 635 /// @param aproof pointer to the proof 636 /// @param nb_public_inputs number of public inputs 637 /// @param mPtr pointer to free memory 638 /// @return pi_commit custom gate public inputs contribution 639 function sum_pi_commit(aproof, nb_public_inputs, mPtr)->pi_commit { 640 641 let state := mload(0x40) 642 let z := mload(add(state, STATE_ZETA)) 643 let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) 644 645 let p := add(aproof, PROOF_BSB_COMMITMENTS) 646 647 let h_fr, ith_lagrange 648 649 {{ range $index, $element := .Vk.CommitmentConstraintIndexes}} 650 h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr) 651 ith_lagrange := compute_ith_lagrange_at_z(z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API_{{ $index }}), mPtr) 652 pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD) 653 {{ if (lt (inc $index) (len $.Vk.CommitmentConstraintIndexes) )}} 654 p := add(p, 0x40) 655 {{ end }} 656 {{ end }} 657 658 } 659 660 /// Computes L_i(zeta) = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) where: 661 /// @param z zeta 662 /// @param zpmno ζⁿ-1 663 /// @param i i-th lagrange 664 /// @param mPtr free memory 665 /// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) 666 function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr)->res { 667 668 let w := pow(VK_OMEGA, i, mPtr) // w**i 669 i := addmod(z, sub(R_MOD, w), R_MOD) // z-w**i 670 w := mulmod(w, VK_INV_DOMAIN_SIZE, R_MOD) // w**i/n 671 i := pow(i, sub(R_MOD,2), mPtr) // (z-w**i)**-1 672 w := mulmod(w, i, R_MOD) // w**i/n*(z-w)**-1 673 res := mulmod(w, zpnmo, R_MOD) 674 675 } 676 677 /// @dev https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 678 /// @param x x coordinate of a point on Bn254(𝔽_p) 679 /// @param y y coordinate of a point on Bn254(𝔽_p) 680 /// @param mPtr free memory 681 /// @return res an element mod R_MOD 682 function hash_fr(x, y, mPtr)->res { 683 684 // [0x00, .. , 0x00 || x, y, || 0, 48, 0, dst, HASH_FR_SIZE_DOMAIN] 685 // <- 64 bytes -> <-64b -> <- 1 bytes each -> 686 687 // [0x00, .., 0x00] 64 bytes of zero 688 mstore(mPtr, HASH_FR_ZERO_UINT256) 689 mstore(add(mPtr, 0x20), HASH_FR_ZERO_UINT256) 690 691 // msg = x || y , both on 32 bytes 692 mstore(add(mPtr, 0x40), x) 693 mstore(add(mPtr, 0x60), y) 694 695 // 0 || 48 || 0 all on 1 byte 696 mstore8(add(mPtr, 0x80), 0) 697 mstore8(add(mPtr, 0x81), HASH_FR_LEN_IN_BYTES) 698 mstore8(add(mPtr, 0x82), 0) 699 700 // "BSB22-Plonk" = [42, 53, 42, 32, 32, 2d, 50, 6c, 6f, 6e, 6b,] 701 mstore8(add(mPtr, 0x83), 0x42) 702 mstore8(add(mPtr, 0x84), 0x53) 703 mstore8(add(mPtr, 0x85), 0x42) 704 mstore8(add(mPtr, 0x86), 0x32) 705 mstore8(add(mPtr, 0x87), 0x32) 706 mstore8(add(mPtr, 0x88), 0x2d) 707 mstore8(add(mPtr, 0x89), 0x50) 708 mstore8(add(mPtr, 0x8a), 0x6c) 709 mstore8(add(mPtr, 0x8b), 0x6f) 710 mstore8(add(mPtr, 0x8c), 0x6e) 711 mstore8(add(mPtr, 0x8d), 0x6b) 712 713 // size domain 714 mstore8(add(mPtr, 0x8e), HASH_FR_SIZE_DOMAIN) 715 716 let l_success := staticcall(gas(), SHA2, mPtr, 0x8f, mPtr, 0x20) 717 if iszero(l_success) { 718 error_verify() 719 } 720 721 let b0 := mload(mPtr) 722 723 // [b0 || one || dst || HASH_FR_SIZE_DOMAIN] 724 // <-64bytes -> <- 1 byte each -> 725 mstore8(add(mPtr, 0x20), HASH_FR_ONE) // 1 726 727 mstore8(add(mPtr, 0x21), 0x42) // dst 728 mstore8(add(mPtr, 0x22), 0x53) 729 mstore8(add(mPtr, 0x23), 0x42) 730 mstore8(add(mPtr, 0x24), 0x32) 731 mstore8(add(mPtr, 0x25), 0x32) 732 mstore8(add(mPtr, 0x26), 0x2d) 733 mstore8(add(mPtr, 0x27), 0x50) 734 mstore8(add(mPtr, 0x28), 0x6c) 735 mstore8(add(mPtr, 0x29), 0x6f) 736 mstore8(add(mPtr, 0x2a), 0x6e) 737 mstore8(add(mPtr, 0x2b), 0x6b) 738 739 mstore8(add(mPtr, 0x2c), HASH_FR_SIZE_DOMAIN) // size domain 740 l_success := staticcall(gas(), SHA2, mPtr, 0x2d, mPtr, 0x20) 741 if iszero(l_success) { 742 error_verify() 743 } 744 745 // b1 is located at mPtr. We store b2 at add(mPtr, 0x20) 746 747 // [b0^b1 || two || dst || HASH_FR_SIZE_DOMAIN] 748 // <-64bytes -> <- 1 byte each -> 749 mstore(add(mPtr, 0x20), xor(mload(mPtr), b0)) 750 mstore8(add(mPtr, 0x40), HASH_FR_TWO) 751 752 mstore8(add(mPtr, 0x41), 0x42) // dst 753 mstore8(add(mPtr, 0x42), 0x53) 754 mstore8(add(mPtr, 0x43), 0x42) 755 mstore8(add(mPtr, 0x44), 0x32) 756 mstore8(add(mPtr, 0x45), 0x32) 757 mstore8(add(mPtr, 0x46), 0x2d) 758 mstore8(add(mPtr, 0x47), 0x50) 759 mstore8(add(mPtr, 0x48), 0x6c) 760 mstore8(add(mPtr, 0x49), 0x6f) 761 mstore8(add(mPtr, 0x4a), 0x6e) 762 mstore8(add(mPtr, 0x4b), 0x6b) 763 764 mstore8(add(mPtr, 0x4c), HASH_FR_SIZE_DOMAIN) // size domain 765 766 let offset := add(mPtr, 0x20) 767 l_success := staticcall(gas(), SHA2, offset, 0x2d, offset, 0x20) 768 if iszero(l_success) { 769 error_verify() 770 } 771 772 // at this point we have mPtr = [ b1 || b2] where b1 is on 32byes and b2 in 16bytes. 773 // we interpret it as a big integer mod r in big endian (similar to regular decimal notation) 774 // the result is then 2**(8*16)*mPtr[:32] + mPtr[32:48] 775 res := mulmod(mload(mPtr), HASH_FR_BB, R_MOD) // <- res = 2**128 * mPtr[:32] 776 let b1 := shr(128, mload(add(mPtr, 0x20))) // b1 <- [0, 0, .., 0 || b2[:16] ] 777 res := addmod(res, b1, R_MOD) 778 779 } 780 {{ end }} 781 // END compute_pi ------------------------------------------------- 782 783 /// @notice compute α² * 1/n * (ζ{n}-1)/(ζ - 1) where 784 /// * α = challenge derived in derive_gamma_beta_alpha_zeta 785 /// * n = vk_domain_size 786 /// * ω = vk_omega (generator of the multiplicative cyclic group of order n in (ℤ/rℤ)*) 787 /// * ζ = zeta (challenge derived with Fiat Shamir) 788 function compute_alpha_square_lagrange_0() { 789 let state := mload(0x40) 790 let mPtr := add(mload(0x40), STATE_LAST_MEM) 791 792 let res := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)) 793 let den := addmod(mload(add(state, STATE_ZETA)), sub(R_MOD, 1), R_MOD) 794 den := pow(den, sub(R_MOD, 2), mPtr) 795 den := mulmod(den, VK_INV_DOMAIN_SIZE, R_MOD) 796 res := mulmod(den, res, R_MOD) 797 798 let l_alpha := mload(add(state, STATE_ALPHA)) 799 res := mulmod(res, l_alpha, R_MOD) 800 res := mulmod(res, l_alpha, R_MOD) 801 mstore(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0), res) 802 } 803 804 /// @notice follows alg. p.13 of https://eprint.iacr.org/2019/953.pdf 805 /// with t₁ = t₂ = 1, and the proofs are ([digest] + [quotient] +purported evaluation): 806 /// * [state_folded_state_digests], [proof_batch_opening_at_zeta_x], state_folded_evals 807 /// * [proof_grand_product_commitment], [proof_opening_at_zeta_omega_x], [proof_grand_product_at_zeta_omega] 808 /// @param aproof pointer to the proof 809 function batch_verify_multi_points(aproof) { 810 let state := mload(0x40) 811 let mPtr := add(state, STATE_LAST_MEM) 812 813 // derive a random number. As there is no random generator, we 814 // do an FS like challenge derivation, depending on both digests and 815 // ζ to ensure that the prover cannot control the random number. 816 // Note: adding the other point ζω is not needed, as ω is known beforehand. 817 mstore(mPtr, mload(add(state, STATE_FOLDED_DIGESTS_X))) 818 mstore(add(mPtr, 0x20), mload(add(state, STATE_FOLDED_DIGESTS_Y))) 819 mstore(add(mPtr, 0x40), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X))) 820 mstore(add(mPtr, 0x60), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y))) 821 mstore(add(mPtr, 0x80), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X))) 822 mstore(add(mPtr, 0xa0), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y))) 823 mstore(add(mPtr, 0xc0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X))) 824 mstore(add(mPtr, 0xe0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_Y))) 825 mstore(add(mPtr, 0x100), mload(add(state, STATE_ZETA))) 826 mstore(add(mPtr, 0x120), mload(add(state, STATE_GAMMA_KZG))) 827 let random := staticcall(gas(), SHA2, mPtr, 0x140, mPtr, 0x20) 828 if iszero(random){ 829 error_random_generation() 830 } 831 random := mod(mload(mPtr), R_MOD) // use the same variable as we are one variable away from getting stack-too-deep error... 832 833 let folded_quotients := mPtr 834 mPtr := add(folded_quotients, 0x40) 835 mstore(folded_quotients, calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X))) 836 mstore(add(folded_quotients, 0x20), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y))) 837 point_acc_mul_calldata(folded_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr) 838 839 let folded_digests := add(state, STATE_FOLDED_DIGESTS_X) 840 point_acc_mul_calldata(folded_digests, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), random, mPtr) 841 842 let folded_evals := add(state, STATE_FOLDED_CLAIMED_VALUES) 843 fr_acc_mul_calldata(folded_evals, add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA), random) 844 845 let folded_evals_commit := mPtr 846 mPtr := add(folded_evals_commit, 0x40) 847 mstore(folded_evals_commit, G1_SRS_X) 848 mstore(add(folded_evals_commit, 0x20), G1_SRS_Y) 849 mstore(add(folded_evals_commit, 0x40), mload(folded_evals)) 850 let check_staticcall := staticcall(gas(), 7, folded_evals_commit, 0x60, folded_evals_commit, 0x40) 851 if iszero(check_staticcall) { 852 error_verify() 853 } 854 855 let folded_evals_commit_y := add(folded_evals_commit, 0x20) 856 mstore(folded_evals_commit_y, sub(P_MOD, mload(folded_evals_commit_y))) 857 point_add(folded_digests, folded_digests, folded_evals_commit, mPtr) 858 859 let folded_points_quotients := mPtr 860 mPtr := add(mPtr, 0x40) 861 point_mul_calldata( 862 folded_points_quotients, 863 add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X), 864 mload(add(state, STATE_ZETA)), 865 mPtr 866 ) 867 let zeta_omega := mulmod(mload(add(state, STATE_ZETA)), VK_OMEGA, R_MOD) 868 random := mulmod(random, zeta_omega, R_MOD) 869 point_acc_mul_calldata(folded_points_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr) 870 871 point_add(folded_digests, folded_digests, folded_points_quotients, mPtr) 872 873 let folded_quotients_y := add(folded_quotients, 0x20) 874 mstore(folded_quotients_y, sub(P_MOD, mload(folded_quotients_y))) 875 876 mstore(mPtr, mload(folded_digests)) 877 {{ $offset = 0x20 }} 878 mstore(add(mPtr, {{ hex $offset }}), mload(add(folded_digests, 0x20))) {{ $offset = add $offset 0x20 }} 879 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_0_X_0) {{ $offset = add $offset 0x20 }} // the 4 lines are the canonical G2 point on BN254 880 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_0_X_1) {{ $offset = add $offset 0x20 }} 881 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_0_Y_0) {{ $offset = add $offset 0x20 }} 882 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_0_Y_1) {{ $offset = add $offset 0x20 }} 883 mstore(add(mPtr, {{ hex $offset }}), mload(folded_quotients)) {{ $offset = add $offset 0x20 }} 884 mstore(add(mPtr, {{ hex $offset }}), mload(add(folded_quotients, 0x20))) {{ $offset = add $offset 0x20 }} 885 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_1_X_0) {{ $offset = add $offset 0x20 }} 886 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_1_X_1) {{ $offset = add $offset 0x20 }} 887 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_1_Y_0) {{ $offset = add $offset 0x20 }} 888 mstore(add(mPtr, {{ hex $offset }}), G2_SRS_1_Y_1) {{ $offset = add $offset 0x20 }} 889 check_pairing_kzg(mPtr) 890 } 891 892 /// @notice check_pairing_kzg checks the result of the final pairing product of the batched 893 /// kzg verification. The purpose of this function is to avoid exhausting the stack 894 /// in the function batch_verify_multi_points. 895 /// @param mPtr pointer storing the tuple of pairs 896 function check_pairing_kzg(mPtr) { 897 let state := mload(0x40) 898 899 let l_success := staticcall(gas(), 8, mPtr, 0x180, 0x00, 0x20) 900 if iszero(l_success) { 901 error_pairing() 902 } 903 let res_pairing := mload(0x00) 904 mstore(add(state, STATE_SUCCESS), res_pairing) 905 } 906 907 /// @notice Fold the opening proofs at ζ: 908 /// * at state+state_folded_digest we store: [Linearised_polynomial]+γ[L] + γ²[R] + γ³[O] + γ⁴[S₁] +γ⁵[S₂] + ∑ᵢγ⁵⁺ⁱ[Pi_{i}] 909 /// * at state+state_folded_claimed_values we store: Linearised_polynomial(ζ)+γL(ζ) + γ²R(ζ)+ γ³O(ζ) + γ⁴S₁(ζ) +γ⁵S₂(ζ) + ∑ᵢγ⁵⁺ⁱPi_{i}(ζ) 910 /// @param aproof pointer to the proof 911 /// acc_gamma stores the γⁱ 912 function fold_state(aproof) { 913 914 let state := mload(0x40) 915 let mPtr := add(mload(0x40), STATE_LAST_MEM) 916 let mPtr20 := add(mPtr, 0x20) 917 let mPtr40 := add(mPtr, 0x40) 918 919 let l_gamma_kzg := mload(add(state, STATE_GAMMA_KZG)) 920 let acc_gamma := l_gamma_kzg 921 let state_folded_digests := add(state, STATE_FOLDED_DIGESTS_X) 922 923 mstore(state_folded_digests, mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) 924 mstore(add(state, STATE_FOLDED_DIGESTS_Y), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) 925 mstore(add(state, STATE_FOLDED_CLAIMED_VALUES), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA))) 926 927 point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_L_COM_X), acc_gamma, mPtr) 928 fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_L_AT_ZETA), acc_gamma) 929 930 acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) 931 point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_R_COM_X), acc_gamma, mPtr) 932 fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_R_AT_ZETA), acc_gamma) 933 934 acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) 935 point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_O_COM_X), acc_gamma, mPtr) 936 fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_O_AT_ZETA), acc_gamma) 937 938 acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) 939 mstore(mPtr, VK_S1_COM_X) 940 mstore(mPtr20, VK_S1_COM_Y) 941 point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) 942 fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S1_AT_ZETA), acc_gamma) 943 944 acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) 945 mstore(mPtr, VK_S2_COM_X) 946 mstore(mPtr20, VK_S2_COM_Y) 947 point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) 948 fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S2_AT_ZETA), acc_gamma) 949 950 {{- if (gt (len .Vk.CommitmentConstraintIndexes) 0 ) }} 951 let poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) 952 {{ range $index, $element := .Vk.CommitmentConstraintIndexes }} 953 acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) 954 mstore(mPtr, VK_QCP_{{ $index }}_X) 955 mstore(mPtr20, VK_QCP_{{ $index }}_Y) 956 point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) 957 fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), poqaz, acc_gamma) 958 poqaz := add(poqaz, 0x20) 959 {{ end }} 960 {{ end -}} 961 } 962 963 /// @notice generate the challenge (using Fiat Shamir) to fold the opening proofs 964 /// at ζ. 965 /// The process for deriving γ is the same as in derive_gamma but this time the inputs are 966 /// in this order (the [] means it's a commitment): 967 /// * ζ 968 /// * [Linearised polynomial] 969 /// * [L], [R], [O] 970 /// * [S₁] [S₂] 971 /// * [Pi_{i}] (wires associated to custom gates) 972 /// Then there are the purported evaluations of the previous committed polynomials: 973 /// * Linearised_polynomial(ζ) 974 /// * L(ζ), R(ζ), O(ζ), S₁(ζ), S₂(ζ) 975 /// * Pi_{i}(ζ) 976 /// * Z(ζω) 977 /// @param aproof pointer to the proof 978 function compute_gamma_kzg(aproof) { 979 980 let state := mload(0x40) 981 let mPtr := add(mload(0x40), STATE_LAST_MEM) 982 mstore(mPtr, FS_GAMMA_KZG) // "gamma" 983 mstore(add(mPtr, 0x20), mload(add(state, STATE_ZETA))) 984 mstore(add(mPtr,0x40), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X))) 985 mstore(add(mPtr,0x60), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y))) 986 calldatacopy(add(mPtr, 0x80), add(aproof, PROOF_L_COM_X), 0xc0) 987 mstore(add(mPtr,0x140), VK_S1_COM_X) 988 mstore(add(mPtr,0x160), VK_S1_COM_Y) 989 mstore(add(mPtr,0x180), VK_S2_COM_X) 990 mstore(add(mPtr,0x1a0), VK_S2_COM_Y) 991 992 let offset := 0x1c0 993 994 {{ range $index, $element := .Vk.CommitmentConstraintIndexes -}} 995 mstore(add(mPtr,offset), VK_QCP_{{ $index }}_X) 996 mstore(add(mPtr,add(offset, 0x20)), VK_QCP_{{ $index }}_Y) 997 offset := add(offset, 0x40) 998 {{ end -}} 999 1000 mstore(add(mPtr, offset), mload(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA))) 1001 mstore(add(mPtr, add(offset, 0x20)), calldataload(add(aproof, PROOF_L_AT_ZETA))) 1002 mstore(add(mPtr, add(offset, 0x40)), calldataload(add(aproof, PROOF_R_AT_ZETA))) 1003 mstore(add(mPtr, add(offset, 0x60)), calldataload(add(aproof, PROOF_O_AT_ZETA))) 1004 mstore(add(mPtr, add(offset, 0x80)), calldataload(add(aproof, PROOF_S1_AT_ZETA))) 1005 mstore(add(mPtr, add(offset, 0xa0)), calldataload(add(aproof, PROOF_S2_AT_ZETA))) 1006 1007 let _mPtr := add(mPtr, add(offset, 0xc0)) 1008 1009 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} 1010 let _poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) 1011 calldatacopy(_mPtr, _poqaz, mul(VK_NB_CUSTOM_GATES, 0x20)) 1012 _mPtr := add(_mPtr, mul(VK_NB_CUSTOM_GATES, 0x20)) 1013 {{ end }} 1014 1015 mstore(_mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA))) 1016 1017 let start_input := 0x1b // 00.."gamma" 1018 let size_input := add(0x14, mul(VK_NB_CUSTOM_GATES,3)) // number of 32bytes elmts = 0x14 (zeta+3*6 for the digests+openings) + 3*VK_NB_CUSTOM_GATES (for the commitments of the selectors) + 1 (opening of Z at ζω) 1019 size_input := add(0x5, mul(size_input, 0x20)) // size in bytes: 15*32 bytes + 5 bytes for gamma 1020 let check_staticcall := staticcall(gas(), SHA2, add(mPtr,start_input), size_input, add(state, STATE_GAMMA_KZG), 0x20) 1021 if iszero(check_staticcall) { 1022 error_verify() 1023 } 1024 mstore(add(state, STATE_GAMMA_KZG), mod(mload(add(state, STATE_GAMMA_KZG)), R_MOD)) 1025 } 1026 1027 function compute_commitment_linearised_polynomial_ec(aproof, s1, s2) { 1028 1029 let state := mload(0x40) 1030 let mPtr := add(mload(0x40), STATE_LAST_MEM) 1031 1032 mstore(mPtr, VK_QL_COM_X) 1033 mstore(add(mPtr, 0x20), VK_QL_COM_Y) 1034 point_mul( 1035 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1036 mPtr, 1037 calldataload(add(aproof, PROOF_L_AT_ZETA)), 1038 add(mPtr, 0x40) 1039 ) 1040 1041 mstore(mPtr, VK_QR_COM_X) 1042 mstore(add(mPtr, 0x20), VK_QR_COM_Y) 1043 point_acc_mul( 1044 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1045 mPtr, 1046 calldataload(add(aproof, PROOF_R_AT_ZETA)), 1047 add(mPtr, 0x40) 1048 ) 1049 1050 let rl := mulmod(calldataload(add(aproof, PROOF_L_AT_ZETA)), calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) 1051 mstore(mPtr, VK_QM_COM_X) 1052 mstore(add(mPtr, 0x20), VK_QM_COM_Y) 1053 point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, rl, add(mPtr, 0x40)) 1054 1055 mstore(mPtr, VK_QO_COM_X) 1056 mstore(add(mPtr, 0x20), VK_QO_COM_Y) 1057 point_acc_mul( 1058 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1059 mPtr, 1060 calldataload(add(aproof, PROOF_O_AT_ZETA)), 1061 add(mPtr, 0x40) 1062 ) 1063 1064 mstore(mPtr, VK_QK_COM_X) 1065 mstore(add(mPtr, 0x20), VK_QK_COM_Y) 1066 point_add( 1067 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1068 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1069 mPtr, 1070 add(mPtr, 0x40) 1071 ) 1072 1073 {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} 1074 let qcp_opening_at_zeta := add(aproof, PROOF_OPENING_QCP_AT_ZETA) 1075 let bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) 1076 for { 1077 let i := 0 1078 } lt(i, VK_NB_CUSTOM_GATES) { 1079 i := add(i, 1) 1080 } { 1081 mstore(mPtr, calldataload(bsb_commitments)) 1082 mstore(add(mPtr, 0x20), calldataload(add(bsb_commitments, 0x20))) 1083 point_acc_mul( 1084 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1085 mPtr, 1086 calldataload(qcp_opening_at_zeta), 1087 add(mPtr, 0x40) 1088 ) 1089 qcp_opening_at_zeta := add(qcp_opening_at_zeta, 0x20) 1090 bsb_commitments := add(bsb_commitments, 0x40) 1091 } 1092 {{ end }} 1093 1094 mstore(mPtr, VK_S3_COM_X) 1095 mstore(add(mPtr, 0x20), VK_S3_COM_Y) 1096 point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s1, add(mPtr, 0x40)) 1097 1098 mstore(mPtr, calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X))) 1099 mstore(add(mPtr, 0x20), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y))) 1100 point_acc_mul(add(state, STATE_LINEARISED_POLYNOMIAL_X), mPtr, s2, add(mPtr, 0x40)) 1101 1102 point_add( 1103 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1104 add(state, STATE_LINEARISED_POLYNOMIAL_X), 1105 add(state, STATE_FOLDED_H_X), 1106 mPtr) 1107 } 1108 1109 /// @notice Compute the commitment to the linearized polynomial equal to 1110 /// L(ζ)[Qₗ]+r(ζ)[Qᵣ]+R(ζ)L(ζ)[Qₘ]+O(ζ)[Qₒ]+[Qₖ]+Σᵢqc'ᵢ(ζ)[BsbCommitmentᵢ] + 1111 /// α*( Z(μζ)(L(ζ)+β*S₁(ζ)+γ)*(R(ζ)+β*S₂(ζ)+γ)[S₃]-[Z](L(ζ)+β*id_{1}(ζ)+γ)*(R(ζ)+β*id_{2}(ζ)+γ)*(O(ζ)+β*id_{3}(ζ)+γ) ) + 1112 /// α²*L₁(ζ)[Z] - Z_{H}(ζ)*(([H₀] + ζᵐ⁺²*[H₁] + ζ²⁽ᵐ⁺²⁾*[H₂]) 1113 /// where 1114 /// * id_1 = id, id_2 = vk_coset_shift*id, id_3 = vk_coset_shift^{2}*id 1115 /// * the [] means that it's a commitment (i.e. a point on Bn254(F_p)) 1116 /// * Z_{H}(ζ) = ζ^n-1 1117 /// @param aproof pointer to the proof 1118 function compute_commitment_linearised_polynomial(aproof) { 1119 let state := mload(0x40) 1120 let l_beta := mload(add(state, STATE_BETA)) 1121 let l_gamma := mload(add(state, STATE_GAMMA)) 1122 let l_zeta := mload(add(state, STATE_ZETA)) 1123 let l_alpha := mload(add(state, STATE_ALPHA)) 1124 1125 let u := mulmod(calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)), l_beta, R_MOD) 1126 let v := mulmod(l_beta, calldataload(add(aproof, PROOF_S1_AT_ZETA)), R_MOD) 1127 v := addmod(v, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD) 1128 v := addmod(v, l_gamma, R_MOD) 1129 1130 let w := mulmod(l_beta, calldataload(add(aproof, PROOF_S2_AT_ZETA)), R_MOD) 1131 w := addmod(w, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) 1132 w := addmod(w, l_gamma, R_MOD) 1133 1134 let s1 := mulmod(u, v, R_MOD) 1135 s1 := mulmod(s1, w, R_MOD) 1136 s1 := mulmod(s1, l_alpha, R_MOD) 1137 1138 let coset_square := mulmod(VK_COSET_SHIFT, VK_COSET_SHIFT, R_MOD) 1139 let betazeta := mulmod(l_beta, l_zeta, R_MOD) 1140 u := addmod(betazeta, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD) 1141 u := addmod(u, l_gamma, R_MOD) 1142 1143 v := mulmod(betazeta, VK_COSET_SHIFT, R_MOD) 1144 v := addmod(v, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) 1145 v := addmod(v, l_gamma, R_MOD) 1146 1147 w := mulmod(betazeta, coset_square, R_MOD) 1148 w := addmod(w, calldataload(add(aproof, PROOF_O_AT_ZETA)), R_MOD) 1149 w := addmod(w, l_gamma, R_MOD) 1150 1151 let s2 := mulmod(u, v, R_MOD) 1152 s2 := mulmod(s2, w, R_MOD) 1153 s2 := sub(R_MOD, s2) 1154 s2 := mulmod(s2, l_alpha, R_MOD) 1155 s2 := addmod(s2, mload(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0)), R_MOD) 1156 1157 // at this stage: 1158 // * s₁ = α*Z(μζ)(l(ζ)+β*s₁(ζ)+γ)*(r(ζ)+β*s₂(ζ)+γ)*β 1159 // * s₂ = -α*(l(ζ)+β*ζ+γ)*(r(ζ)+β*u*ζ+γ)*(o(ζ)+β*u²*ζ+γ) + α²*L₁(ζ) 1160 1161 compute_commitment_linearised_polynomial_ec(aproof, s1, s2) 1162 } 1163 1164 /// @notice compute -z_h(ζ)*([H₁] + ζⁿ⁺²[H₂] + ζ²⁽ⁿ⁺²⁾[H₃]) and store the result at 1165 /// state + state_folded_h 1166 /// @param aproof pointer to the proof 1167 function fold_h(aproof) { 1168 let state := mload(0x40) 1169 let n_plus_two := add(VK_DOMAIN_SIZE, 2) 1170 let mPtr := add(mload(0x40), STATE_LAST_MEM) 1171 let zeta_power_n_plus_two := pow(mload(add(state, STATE_ZETA)), n_plus_two, mPtr) 1172 point_mul_calldata(add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_2_COM_X), zeta_power_n_plus_two, mPtr) 1173 point_add_calldata(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_1_COM_X), mPtr) 1174 point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), zeta_power_n_plus_two, mPtr) 1175 point_add_calldata(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), add(aproof, PROOF_H_0_COM_X), mPtr) 1176 point_mul(add(state, STATE_FOLDED_H_X), add(state, STATE_FOLDED_H_X), mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE)), mPtr) 1177 let folded_h_y := mload(add(state, STATE_FOLDED_H_Y)) 1178 folded_h_y := sub(P_MOD, folded_h_y) 1179 mstore(add(state, STATE_FOLDED_H_Y), folded_h_y) 1180 } 1181 1182 /// @notice check that the opening of the linearised polynomial at zeta is equal to 1183 /// - [ PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) ] 1184 /// @param aproof pointer to the proof 1185 function compute_opening_linearised_polynomial(aproof) { 1186 1187 let state := mload(0x40) 1188 1189 // (l(ζ)+β*s1(ζ)+γ) 1190 let s1 1191 s1 := mulmod(calldataload(add(aproof, PROOF_S1_AT_ZETA)), mload(add(state, STATE_BETA)), R_MOD) 1192 s1 := addmod(s1, mload(add(state, STATE_GAMMA)), R_MOD) 1193 s1 := addmod(s1, calldataload(add(aproof, PROOF_L_AT_ZETA)), R_MOD) 1194 1195 // (r(ζ)+β*s2(ζ)+γ) 1196 let s2 1197 s2 := mulmod(calldataload(add(aproof, PROOF_S2_AT_ZETA)), mload(add(state, STATE_BETA)), R_MOD) 1198 s2 := addmod(s2, mload(add(state, STATE_GAMMA)), R_MOD) 1199 s2 := addmod(s2, calldataload(add(aproof, PROOF_R_AT_ZETA)), R_MOD) 1200 1201 // (o(ζ)+γ) 1202 let o 1203 o := addmod(calldataload(add(aproof, PROOF_O_AT_ZETA)), mload(add(state, STATE_GAMMA)), R_MOD) 1204 1205 // α*Z(μζ)*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) 1206 s1 := mulmod(s1, s2, R_MOD) 1207 s1 := mulmod(s1, o, R_MOD) 1208 s1 := mulmod(s1, mload(add(state, STATE_ALPHA)), R_MOD) 1209 s1 := mulmod(s1, calldataload(add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)), R_MOD) 1210 1211 // PI(ζ) - α²*L₁(ζ) + α(l(ζ)+β*s1(ζ)+γ)(r(ζ)+β*s2(ζ)+γ)(o(ζ)+γ)*z(ωζ) 1212 s1 := addmod(s1, mload(add(state, STATE_PI)), R_MOD) 1213 s2 := mload(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0)) 1214 s2 := sub(R_MOD, s2) 1215 s1 := addmod(s1, s2, R_MOD) 1216 s1 := sub(R_MOD, s1) 1217 1218 mstore(add(state, STATE_OPENING_LINEARISED_POLYNOMIAL_ZETA), s1) 1219 } 1220 1221 // BEGINNING utils math functions ------------------------------------------------- 1222 1223 /// @param dst pointer storing the result 1224 /// @param p pointer to the first point 1225 /// @param q pointer to the second point 1226 /// @param mPtr pointer to free memory 1227 function point_add(dst, p, q, mPtr) { 1228 mstore(mPtr, mload(p)) 1229 mstore(add(mPtr, 0x20), mload(add(p, 0x20))) 1230 mstore(add(mPtr, 0x40), mload(q)) 1231 mstore(add(mPtr, 0x60), mload(add(q, 0x20))) 1232 let l_success := staticcall(gas(),EC_ADD,mPtr,0x80,dst,0x40) 1233 if iszero(l_success) { 1234 error_ec_op() 1235 } 1236 } 1237 1238 /// @param dst pointer storing the result 1239 /// @param p pointer to the first point (calldata) 1240 /// @param q pointer to the second point (calladata) 1241 /// @param mPtr pointer to free memory 1242 function point_add_calldata(dst, p, q, mPtr) { 1243 mstore(mPtr, mload(p)) 1244 mstore(add(mPtr, 0x20), mload(add(p, 0x20))) 1245 mstore(add(mPtr, 0x40), calldataload(q)) 1246 mstore(add(mPtr, 0x60), calldataload(add(q, 0x20))) 1247 let l_success := staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40) 1248 if iszero(l_success) { 1249 error_ec_op() 1250 } 1251 } 1252 1253 /// @parma dst pointer storing the result 1254 /// @param src pointer to a point on Bn254(𝔽_p) 1255 /// @param s scalar 1256 /// @param mPtr free memory 1257 function point_mul(dst,src,s, mPtr) { 1258 mstore(mPtr,mload(src)) 1259 mstore(add(mPtr,0x20),mload(add(src,0x20))) 1260 mstore(add(mPtr,0x40),s) 1261 let l_success := staticcall(gas(),EC_MUL,mPtr,0x60,dst,0x40) 1262 if iszero(l_success) { 1263 error_ec_op() 1264 } 1265 } 1266 1267 /// @parma dst pointer storing the result 1268 /// @param src pointer to a point on Bn254(𝔽_p) on calldata 1269 /// @param s scalar 1270 /// @param mPtr free memory 1271 function point_mul_calldata(dst, src, s, mPtr) { 1272 mstore(mPtr, calldataload(src)) 1273 mstore(add(mPtr, 0x20), calldataload(add(src, 0x20))) 1274 mstore(add(mPtr, 0x40), s) 1275 let l_success := staticcall(gas(), EC_MUL, mPtr, 0x60, dst, 0x40) 1276 if iszero(l_success) { 1277 error_ec_op() 1278 } 1279 } 1280 1281 /// @notice dst <- dst + [s]src (Elliptic curve) 1282 /// @param dst pointer accumulator point storing the result 1283 /// @param src pointer to the point to multiply and add 1284 /// @param s scalar 1285 /// @param mPtr free memory 1286 function point_acc_mul(dst,src,s, mPtr) { 1287 mstore(mPtr,mload(src)) 1288 mstore(add(mPtr,0x20),mload(add(src,0x20))) 1289 mstore(add(mPtr,0x40),s) 1290 let l_success := staticcall(gas(),7,mPtr,0x60,mPtr,0x40) 1291 mstore(add(mPtr,0x40),mload(dst)) 1292 mstore(add(mPtr,0x60),mload(add(dst,0x20))) 1293 l_success := and(l_success, staticcall(gas(),EC_ADD,mPtr,0x80,dst, 0x40)) 1294 if iszero(l_success) { 1295 error_ec_op() 1296 } 1297 } 1298 1299 /// @notice dst <- dst + [s]src (Elliptic curve) 1300 /// @param dst pointer accumulator point storing the result 1301 /// @param src pointer to the point to multiply and add (on calldata) 1302 /// @param s scalar 1303 /// @mPtr free memory 1304 function point_acc_mul_calldata(dst, src, s, mPtr) { 1305 mstore(mPtr, calldataload(src)) 1306 mstore(add(mPtr, 0x20), calldataload(add(src, 0x20))) 1307 mstore(add(mPtr, 0x40), s) 1308 let l_success := staticcall(gas(), 7, mPtr, 0x60, mPtr, 0x40) 1309 mstore(add(mPtr, 0x40), mload(dst)) 1310 mstore(add(mPtr, 0x60), mload(add(dst, 0x20))) 1311 l_success := and(l_success, staticcall(gas(), EC_ADD, mPtr, 0x80, dst, 0x40)) 1312 if iszero(l_success) { 1313 error_ec_op() 1314 } 1315 } 1316 1317 /// @notice dst <- dst + src*s (Fr) dst,src are addresses, s is a value 1318 /// @param dst pointer storing the result 1319 /// @param src pointer to the scalar to multiply and add (on calldata) 1320 /// @param s scalar 1321 function fr_acc_mul_calldata(dst, src, s) { 1322 let tmp := mulmod(calldataload(src), s, R_MOD) 1323 mstore(dst, addmod(mload(dst), tmp, R_MOD)) 1324 } 1325 1326 /// @param x element to exponentiate 1327 /// @param e exponent 1328 /// @param mPtr free memory 1329 /// @return res x ** e mod r 1330 function pow(x, e, mPtr)->res { 1331 mstore(mPtr, 0x20) 1332 mstore(add(mPtr, 0x20), 0x20) 1333 mstore(add(mPtr, 0x40), 0x20) 1334 mstore(add(mPtr, 0x60), x) 1335 mstore(add(mPtr, 0x80), e) 1336 mstore(add(mPtr, 0xa0), R_MOD) 1337 let check_staticcall := staticcall(gas(),MOD_EXP,mPtr,0xc0,mPtr,0x20) 1338 if eq(check_staticcall, 0) { 1339 error_mod_exp() 1340 } 1341 res := mload(mPtr) 1342 } 1343 } 1344 } 1345 } 1346 ` 1347 1348 // MarshalSolidity converts a proof to a byte array that can be used in a 1349 // Solidity contract. 1350 func (proof *Proof) MarshalSolidity() []byte { 1351 1352 res := make([]byte, 0, 1024) 1353 1354 // uint256 l_com_x; 1355 // uint256 l_com_y; 1356 // uint256 r_com_x; 1357 // uint256 r_com_y; 1358 // uint256 o_com_x; 1359 // uint256 o_com_y; 1360 var tmp64 [64]byte 1361 for i := 0; i < 3; i++ { 1362 tmp64 = proof.LRO[i].RawBytes() 1363 res = append(res, tmp64[:]...) 1364 } 1365 1366 // uint256 h_0_x; 1367 // uint256 h_0_y; 1368 // uint256 h_1_x; 1369 // uint256 h_1_y; 1370 // uint256 h_2_x; 1371 // uint256 h_2_y; 1372 for i := 0; i < 3; i++ { 1373 tmp64 = proof.H[i].RawBytes() 1374 res = append(res, tmp64[:]...) 1375 } 1376 var tmp32 [32]byte 1377 1378 // uint256 l_at_zeta; 1379 // uint256 r_at_zeta; 1380 // uint256 o_at_zeta; 1381 // uint256 s1_at_zeta; 1382 // uint256 s2_at_zeta; 1383 for i := 1; i < 6; i++ { 1384 tmp32 = proof.BatchedProof.ClaimedValues[i].Bytes() 1385 res = append(res, tmp32[:]...) 1386 } 1387 1388 // uint256 grand_product_commitment_x; 1389 // uint256 grand_product_commitment_y; 1390 tmp64 = proof.Z.RawBytes() 1391 res = append(res, tmp64[:]...) 1392 1393 // uint256 grand_product_at_zeta_omega; 1394 tmp32 = proof.ZShiftedOpening.ClaimedValue.Bytes() 1395 res = append(res, tmp32[:]...) 1396 1397 // we skip the claimed value of the linearised polynomial at zeta because it 1398 // is recomputed by the verifier and plugged in the batch opening proof directly 1399 1400 // uint256 opening_at_zeta_proof_x; 1401 // uint256 opening_at_zeta_proof_y; 1402 tmp64 = proof.BatchedProof.H.RawBytes() 1403 res = append(res, tmp64[:]...) 1404 1405 // uint256 opening_at_zeta_omega_proof_x; 1406 // uint256 opening_at_zeta_omega_proof_y; 1407 tmp64 = proof.ZShiftedOpening.H.RawBytes() 1408 res = append(res, tmp64[:]...) 1409 1410 // uint256[] selector_commit_api_at_zeta; 1411 // uint256[] wire_committed_commitments; 1412 for i := 0; i < len(proof.Bsb22Commitments); i++ { 1413 tmp32 = proof.BatchedProof.ClaimedValues[6+i].Bytes() 1414 res = append(res, tmp32[:]...) 1415 } 1416 1417 for _, bc := range proof.Bsb22Commitments { 1418 tmp64 = bc.RawBytes() 1419 res = append(res, tmp64[:]...) 1420 } 1421 1422 return res 1423 }