diff --git a/loader.py b/loader.py index 3b05728..bafa40f 100644 --- a/loader.py +++ b/loader.py @@ -236,6 +236,12 @@ def formatNumber(num): f_W_snark_secondary_eval_row = f_W_snark_secondary['eval_row'] f_W_snark_secondary_eval_E_row_at_r_prod = f_W_snark_secondary['eval_E_row_at_r_prod'] f_W_snark_secondary_eval_row_read_ts = f_W_snark_secondary['eval_row_read_ts'] +f_W_snark_secondary_eval_col_audit_ts = f_W_snark_secondary['eval_col_audit_ts'] +f_W_snark_secondary_eval_col = f_W_snark_secondary['eval_col'] +f_W_snark_secondary_eval_E_col_at_r_prod = f_W_snark_secondary['eval_E_col_at_r_prod'] +f_W_snark_secondary_eval_col_read_ts = f_W_snark_secondary['eval_col_read_ts'] +f_W_snark_secondary_eval_W = f_W_snark_secondary['eval_W'] + @@ -318,6 +324,12 @@ def formatNumber(num): r_W_snark_primary_eval_row = r_W_snark_primary['eval_row'] r_W_snark_primary_eval_E_row_at_r_prod = r_W_snark_primary['eval_E_row_at_r_prod'] r_W_snark_primary_eval_row_read_ts = r_W_snark_primary['eval_row_read_ts'] +r_W_snark_primary_eval_col_audit_ts = r_W_snark_primary['eval_col_audit_ts'] +r_W_snark_primary_eval_col = r_W_snark_primary['eval_col'] +r_W_snark_primary_eval_E_col_at_r_prod = r_W_snark_primary['eval_E_col_at_r_prod'] +r_W_snark_primary_eval_col_read_ts = r_W_snark_primary['eval_col_read_ts'] +r_W_snark_primary_eval_W = r_W_snark_primary['eval_W'] + ProofData = namedtuple( '_ProofData', ( @@ -372,9 +384,11 @@ def formatNumber(num): 'f_W_snark_secondary_eval_row', 'f_W_snark_secondary_eval_E_row_at_r_prod', 'f_W_snark_secondary_eval_row_read_ts', - - - + 'f_W_snark_secondary_eval_col_audit_ts', + 'f_W_snark_secondary_eval_col', + 'f_W_snark_secondary_eval_E_col_at_r_prod', + 'f_W_snark_secondary_eval_col_read_ts', + 'f_W_snark_secondary_eval_W', 'r_W_snark_primary_comm_Az', @@ -411,6 +425,11 @@ def formatNumber(num): 'r_W_snark_primary_eval_row', 'r_W_snark_primary_eval_E_row_at_r_prod', 'r_W_snark_primary_eval_row_read_ts', + 'r_W_snark_primary_eval_col_audit_ts', + 'r_W_snark_primary_eval_col', + 'r_W_snark_primary_eval_E_col_at_r_prod', + 'r_W_snark_primary_eval_col_read_ts', + 'r_W_snark_primary_eval_W', ) ) @@ -468,8 +487,11 @@ def formatNumber(num): f_W_snark_secondary_eval_row, f_W_snark_secondary_eval_E_row_at_r_prod, f_W_snark_secondary_eval_row_read_ts, - - + f_W_snark_secondary_eval_col_audit_ts, + f_W_snark_secondary_eval_col, + f_W_snark_secondary_eval_E_col_at_r_prod, + f_W_snark_secondary_eval_col_read_ts, + f_W_snark_secondary_eval_W, r_W_snark_primary_comm_Az, @@ -507,6 +529,11 @@ def formatNumber(num): r_W_snark_primary_eval_row, r_W_snark_primary_eval_E_row_at_r_prod, r_W_snark_primary_eval_row_read_ts, + r_W_snark_primary_eval_col_audit_ts, + r_W_snark_primary_eval_col, + r_W_snark_primary_eval_E_col_at_r_prod, + r_W_snark_primary_eval_col_read_ts, + r_W_snark_primary_eval_W, ) VerifierKey = namedtuple ( @@ -550,7 +577,7 @@ def formatNumber(num): ) PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" -CONTRACT_ADDRESS = "0x2bdcc0de6be1f7d2ee689a0342d76f52e8efaba3" +CONTRACT_ADDRESS = "0xc351628eb244ec633d5f21fbd6621e1a683b1181" PUSH_TO_PROOF_FUNC_SIG = "pushToProof((" \ "(uint256,uint256[])," \ @@ -559,8 +586,8 @@ def formatNumber(num): "uint256[]," \ "uint256[]," \ "uint256," \ - "(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256,uint256,uint256,uint256)," \ - "(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256,uint256,uint256,uint256)" \ + "(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)," \ + "(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)" \ "))" PUSH_TO_VK_FUNC_SIG = "pushToVk((uint256,uint256,uint256,(uint256[],uint256[]),(uint256[],uint256[]),((uint256),uint256),(uint256,uint256,(uint256),uint256)))" @@ -641,7 +668,12 @@ def pushToProof(data): command = command + addNumber(data.f_W_snark_secondary_eval_row_audit_ts, True) + ',' command = command + addNumber(data.f_W_snark_secondary_eval_row, True) + ',' command = command + addNumber(data.f_W_snark_secondary_eval_E_row_at_r_prod, True) + ',' - command = command + addNumber(data.f_W_snark_secondary_eval_row_read_ts, True) + '),(' + command = command + addNumber(data.f_W_snark_secondary_eval_row_read_ts, True) + ',' + command = command + addNumber(data.f_W_snark_secondary_eval_col_audit_ts, True) + ',' + command = command + addNumber(data.f_W_snark_secondary_eval_col, True) + ',' + command = command + addNumber(data.f_W_snark_secondary_eval_E_col_at_r_prod, True) + ',' + command = command + addNumber(data.f_W_snark_secondary_eval_col_read_ts, True) + ',' + command = command + addNumber(data.f_W_snark_secondary_eval_W, True) + '),(' command = command + addNumber(data.r_W_snark_primary_comm_Az, False) + ',' command = command + addNumber(data.r_W_snark_primary_comm_Bz, False) + ',' @@ -670,7 +702,12 @@ def pushToProof(data): command = command + addNumber(data.r_W_snark_primary_eval_row_audit_ts, True) + ',' command = command + addNumber(data.r_W_snark_primary_eval_row, True) + ',' command = command + addNumber(data.r_W_snark_primary_eval_E_row_at_r_prod, True) + ',' - command = command + addNumber(data.r_W_snark_primary_eval_row_read_ts, True) + ')' + command = command + addNumber(data.r_W_snark_primary_eval_row_read_ts, True) + ',' + command = command + addNumber(data.r_W_snark_primary_eval_col_audit_ts, True) + ',' + command = command + addNumber(data.r_W_snark_primary_eval_col, True) + ',' + command = command + addNumber(data.r_W_snark_primary_eval_E_col_at_r_prod, True) + ',' + command = command + addNumber(data.r_W_snark_primary_eval_col_read_ts, True) + ',' + command = command + addNumber(data.r_W_snark_primary_eval_W, True) + ')' command = command + ')\" --private-key ' + PRIVATE_KEY #print(command) os.system(command) diff --git a/src/NovaVerifierAbstractions.sol b/src/NovaVerifierAbstractions.sol index 73570bf..57ae8f8 100644 --- a/src/NovaVerifierAbstractions.sol +++ b/src/NovaVerifierAbstractions.sol @@ -55,6 +55,11 @@ library Abstractions { uint256 eval_row; uint256 eval_E_row_at_r_prod; uint256 eval_row_read_ts; + uint256 eval_col_audit_ts; + uint256 eval_col; + uint256 eval_E_col_at_r_prod; + uint256 eval_col_read_ts; + uint256 eval_W; } struct CompressedSnark { diff --git a/src/NovaVerifierContract.sol b/src/NovaVerifierContract.sol index bccea0d..88b2fff 100644 --- a/src/NovaVerifierContract.sol +++ b/src/NovaVerifierContract.sol @@ -9,14 +9,21 @@ import "src/verifier/Step2.sol"; import "src/verifier/Step3.sol"; import "src/verifier/Step4.sol"; import "src/verifier/Step5.sol"; +import "src/verifier/Step6.sol"; import "src/NovaVerifierAbstractions.sol"; contract NovaVerifierContract { + struct Step5IntermediateData { + uint256[] r_prod; + } + struct Step3IntermediateData { uint256[] tau; uint256 gamma1; uint256 gamma2; uint256[] r_sat; + uint256[] U_X; + uint256 U_u; } struct Step3PrecomputeOutput { @@ -26,6 +33,7 @@ contract NovaVerifierContract { uint256[] rand_eq; uint256[] coeffs; uint256 U_u; + uint256[] U_X; uint256 gamma1; uint256 gamma2; } @@ -68,8 +76,7 @@ contract NovaVerifierContract { return (transcriptPrimaryInstance, transcriptSecondaryInstance); } - // cast send 0x7a9ec1d04904907de0ed7b6839ccdd59c3716ac9 "pushToProof(((uint256,uint256[]),(uint256,uint256,uint256[],uint256),(uint256,uint256,uint256[],uint256),uint256[],uint256[],uint256,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint - //256,uint256,uint256,uint256,uint256[],uint256),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256)))" "((1,[1]),(1,1,[1],1),(1,1,[1],1),[1],[1],1,(1,1,1,1,1,1,1,1,[1],[1],([([1])]),[1],[1],[1],1,1,1,1,1,1,1,1,1,[1],1),(1,1,1,1,1,1,1,1,[1],[1],([([1])]),[1],[1],[1],1,1,1,1,1,1,1,1,1,[1],1))" --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + // cast send 0xc351628eb244ec633d5f21fbd6621e1a683b1181 "pushToProof(((uint256,uint256[]),(uint256,uint256,uint256[],uint256),(uint256,uint256,uint256[],uint256),uint256[],uint256[],uint256,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[],((uint256[])[]),uint256[],uint256[],uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[],uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)))" "((1,[1]),(1,1,[1],1),(1,1,[1],1),[1],[1],1,(1,1,1,1,1,1,1,1,[1],[1],([([1])]),[1],[1],[1],1,1,1,1,1,1,1,1,1,[1],1,1,1,1,1,1,1,1,1),(1,1,1,1,1,1,1,1,[1],[1],([([1])]),[1],[1],[1],1,1,1,1,1,1,1,1,1,[1],1,1,1,1,1,1,1,1,1))" --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 function pushToProof(Abstractions.CompressedSnark calldata input) public { proof = input; } @@ -101,6 +108,8 @@ contract NovaVerifierContract { Step3IntermediateData memory step3PrimaryOutput; Step3IntermediateData memory step3SecondaryOutput; + Step5IntermediateData memory step5PrimaryOutput; + Step5IntermediateData memory step5SecondaryOutput; bool success; // fold the running instance and last instance to get a folded instance @@ -128,20 +137,111 @@ contract NovaVerifierContract { } // multiset check for the row - if (!verifyStep5Primary(step3PrimaryOutput)) { + (step5PrimaryOutput, success) = verifyStep5Primary(step3PrimaryOutput); + if (!success) { console.log("[Step5 Primary] false"); return false; } - if (!verifyStep5Secondary(step3SecondaryOutput)) { + (step5SecondaryOutput, success) = verifyStep5Secondary(step3SecondaryOutput); + if (!success) { console.log("[Step5 Secondary] false"); return false; } + // multiset check for the col + if (!verifyStep6Primary(step5PrimaryOutput, step3PrimaryOutput)) { + console.log("[Step6 Primary] false"); + return false; + } + + if (!verifyStep6Secondary(step5SecondaryOutput, step3SecondaryOutput)) { + console.log("[Step6 Secondary] false"); + return false; + } + return true; } - function verifyStep5Primary(Step3IntermediateData memory step3PrimaryOutput) private returns (bool) { + function verifyStep6Secondary(Step5IntermediateData memory step5Output, Step3IntermediateData memory step3Output) + public + returns (bool) + { + uint256[] memory r_prod = step5Output.r_prod; + uint256 gamma1 = step3Output.gamma1; + uint256 gamma2 = step3Output.gamma2; + uint256[] memory U_X = step3Output.U_X; + uint256 U_u = step3Output.U_u; + + uint256 eval_Z = Step6Lib.compute_eval_Z( + proof.f_W_snark_secondary, + U_X, + U_u, + vk.vk_primary.S_comm.N, + vk.vk_primary.num_vars, + r_prod, + Pallas.P_MOD, + Pallas.negateBase + ); + + (uint256 claim_init_expected_col, uint256 claim_audit_expected_col) = Step6Lib.compute_claims_init_audit( + proof.f_W_snark_secondary, gamma1, gamma2, eval_Z, r_prod, Pallas.P_MOD, Pallas.negateBase + ); + + (uint256 claim_read_expected_col, uint256 claim_write_expected_col) = Step6Lib.compute_claims_read_write( + proof.f_W_snark_secondary, gamma1, gamma2, Pallas.P_MOD, Pallas.negateBase + ); + + return Step6Lib.finalVerification( + proof.f_W_snark_secondary, + claim_init_expected_col, + claim_read_expected_col, + claim_write_expected_col, + claim_audit_expected_col + ); + } + + function verifyStep6Primary(Step5IntermediateData memory step5Output, Step3IntermediateData memory step3Output) + private + returns (bool) + { + uint256[] memory r_prod = step5Output.r_prod; + uint256 gamma1 = step3Output.gamma1; + uint256 gamma2 = step3Output.gamma2; + uint256[] memory U_X = step3Output.U_X; + uint256 U_u = step3Output.U_u; + + uint256 eval_Z = Step6Lib.compute_eval_Z( + proof.r_W_snark_primary, + U_X, + U_u, + vk.vk_primary.S_comm.N, + vk.vk_primary.num_vars, + r_prod, + Vesta.P_MOD, + Vesta.negateBase + ); + + (uint256 claim_init_expected_col, uint256 claim_audit_expected_col) = Step6Lib.compute_claims_init_audit( + proof.r_W_snark_primary, gamma1, gamma2, eval_Z, r_prod, Vesta.P_MOD, Vesta.negateBase + ); + + (uint256 claim_read_expected_col, uint256 claim_write_expected_col) = + Step6Lib.compute_claims_read_write(proof.r_W_snark_primary, gamma1, gamma2, Vesta.P_MOD, Vesta.negateBase); + + return Step6Lib.finalVerification( + proof.r_W_snark_primary, + claim_init_expected_col, + claim_read_expected_col, + claim_write_expected_col, + claim_audit_expected_col + ); + } + + function verifyStep5Primary(Step3IntermediateData memory step3PrimaryOutput) + private + returns (Step5IntermediateData memory, bool) + { uint256 c; (transcriptPrimary, c) = Step5Lib.compute_c_primary(proof.r_W_snark_primary, transcriptPrimary); @@ -161,16 +261,22 @@ contract NovaVerifierContract { proof.r_W_snark_primary, step3PrimaryOutput.gamma1, step3PrimaryOutput.gamma2, Vesta.P_MOD, Vesta.negateBase ); - return Step5Lib.final_verification( - proof.r_W_snark_primary, - claim_init_expected_row, - claim_read_expected_row, - claim_write_expected_row, - claim_audit_expected_row + return ( + Step5IntermediateData(r_prod), + Step5Lib.final_verification( + proof.r_W_snark_primary, + claim_init_expected_row, + claim_read_expected_row, + claim_write_expected_row, + claim_audit_expected_row + ) ); } - function verifyStep5Secondary(Step3IntermediateData memory step3SecondaryOutput) private returns (bool) { + function verifyStep5Secondary(Step3IntermediateData memory step3SecondaryOutput) + private + returns (Step5IntermediateData memory, bool) + { uint256 c; (transcriptSecondary, c) = Step5Lib.compute_c_secondary(proof.f_W_snark_secondary, transcriptSecondary); @@ -194,12 +300,15 @@ contract NovaVerifierContract { Pallas.negateBase ); - return Step5Lib.final_verification( - proof.f_W_snark_secondary, - claim_init_expected_row, - claim_read_expected_row, - claim_write_expected_row, - claim_audit_expected_row + return ( + Step5IntermediateData(r_prod), + Step5Lib.final_verification( + proof.f_W_snark_secondary, + claim_init_expected_row, + claim_read_expected_row, + claim_write_expected_row, + claim_audit_expected_row + ) ); } @@ -208,7 +317,12 @@ contract NovaVerifierContract { (uint256[] memory r_sat, bool success) = verifyStep3InnerPrimary(precompute); - return (Step3IntermediateData(precompute.tau, precompute.gamma1, precompute.gamma2, r_sat), success); + return ( + Step3IntermediateData( + precompute.tau, precompute.gamma1, precompute.gamma2, r_sat, precompute.U_X, precompute.U_u + ), + success + ); } function verifyStep3InnerPrimary(Step3PrecomputeOutput memory precompute) @@ -282,6 +396,7 @@ contract NovaVerifierContract { (transcriptPrimary, precomputeOutput.coeffs) = Step3Lib.compute_coeffs_primary(transcriptPrimary); precomputeOutput.U_u = proof.r_U_primary.u; + precomputeOutput.U_X = proof.r_U_primary.X; if (printLogs) { uint256 index = 0; @@ -329,7 +444,12 @@ contract NovaVerifierContract { (uint256[] memory r_sat, bool success) = verifyStep3InnerSecondary(precompute); - return (Step3IntermediateData(precompute.tau, precompute.gamma1, precompute.gamma2, r_sat), success); + return ( + Step3IntermediateData( + precompute.tau, precompute.gamma1, precompute.gamma2, r_sat, precompute.U_X, precompute.U_u + ), + success + ); } function verifyStep3InnerSecondary(Step3PrecomputeOutput memory precompute) @@ -339,7 +459,13 @@ contract NovaVerifierContract { uint256 claim_sat_final; uint256[] memory r_sat; (claim_sat_final, r_sat, transcriptSecondary) = Step3Lib.compute_claim_sat_final_r_sat_secondary( - proof, vk, transcriptSecondary, precompute.u_step3.e, precompute.coeffs, Pallas.P_MOD + proof.f_W_snark_secondary, + vk.vk_secondary, + transcriptSecondary, + precompute.u_step3.e, + precompute.coeffs, + Pallas.P_MOD, + printLogs ); uint256 taus_bound_r_sat = EqPolinomialLib.evaluate(precompute.tau, r_sat, Pallas.P_MOD, Pallas.negateBase); @@ -420,6 +546,7 @@ contract NovaVerifierContract { (transcriptSecondary, precomputeOutput.coeffs) = Step3Lib.compute_coeffs_secondary(transcriptSecondary); precomputeOutput.U_u = f_U_secondary_u; + precomputeOutput.U_X = f_U_secondary_X; if (printLogs) { uint256 index = 0; diff --git a/src/Utilities.sol b/src/Utilities.sol index d341315..c9e4a04 100644 --- a/src/Utilities.sol +++ b/src/Utilities.sol @@ -182,3 +182,36 @@ library Field { return output; } } + +library CommonUtilities { + function log2(uint256 x) public pure returns (uint256 y) { + assembly { + let arg := x + x := sub(x, 1) + x := or(x, div(x, 0x02)) + x := or(x, div(x, 0x04)) + x := or(x, div(x, 0x10)) + x := or(x, div(x, 0x100)) + x := or(x, div(x, 0x10000)) + x := or(x, div(x, 0x100000000)) + x := or(x, div(x, 0x10000000000000000)) + x := or(x, div(x, 0x100000000000000000000000000000000)) + x := add(x, 1) + let m := mload(0x40) + mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) + mstore(add(m, 0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) + mstore(add(m, 0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) + mstore(add(m, 0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) + mstore(add(m, 0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) + mstore(add(m, 0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) + mstore(add(m, 0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) + mstore(add(m, 0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) + mstore(0x40, add(m, 0x100)) + let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff + let shift := 0x100000000000000000000000000000000000000000000000000000000000000 + let a := div(mul(x, magic), shift) + y := div(mload(add(m, sub(255, a))), shift) + y := add(y, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) + } + } +} diff --git a/src/blocks/SparsePolynomial.sol b/src/blocks/SparsePolynomial.sol index 3517209..d3ccac5 100644 --- a/src/blocks/SparsePolynomial.sol +++ b/src/blocks/SparsePolynomial.sol @@ -29,8 +29,8 @@ library SparsePolynomialLib { Z[] memory poly_X, uint256[] memory r_y, uint256 modulus, - function (uint256) pure returns (uint256) negateBase - ) internal pure returns (uint256) { + function (uint256) returns (uint256) negateBase + ) internal returns (uint256) { require(num_vars == r_y.length, "[SparsePolynomialLib.evaluate] num_vars != r_y.length"); uint256 chi = 1; diff --git a/src/verifier/Step3.sol b/src/verifier/Step3.sol index 9fd804e..4270f16 100644 --- a/src/verifier/Step3.sol +++ b/src/verifier/Step3.sol @@ -165,6 +165,30 @@ library Step3Lib { return actual; } + function compute_sumcheck_claim(uint256 claim_inner, uint256[] memory coeffs, uint256 p_modulus) + private + pure + returns (uint256) + { + return mulmod(coeffs[9], claim_inner, p_modulus); + } + + function extract_sumcheck_proof(Abstractions.RelaxedR1CSSNARK calldata proof) + private + pure + returns (SumcheckUtilities.SumcheckProof memory) + { + // TODO: simplify conversions between abstractions + Abstractions.CompressedPolys[] memory polys = proof.sc_sat.compressed_polys; + SumcheckUtilities.CompressedUniPoly[] memory compressed_polys = + new SumcheckUtilities.CompressedUniPoly[](polys.length); + uint256 index = 0; + for (index = 0; index < polys.length; index++) { + compressed_polys[index] = SumcheckUtilities.CompressedUniPoly(polys[index].coeffs_except_linear_term); + } + return SumcheckUtilities.SumcheckProof(compressed_polys); + } + function compute_claim_sat_final_r_sat_primary( Abstractions.RelaxedR1CSSNARK calldata proof, Abstractions.VerifierKeyS1 calldata vk, @@ -174,56 +198,56 @@ library Step3Lib { uint256 p_modulus, bool enableLogging ) public returns (uint256, uint256[] memory, KeccakTranscriptLib.KeccakTranscript memory) { - // TODO: simplify convertions between abstractions - Abstractions.CompressedPolys[] memory polys = proof.sc_sat.compressed_polys; - SumcheckUtilities.CompressedUniPoly[] memory compressed_polys = - new SumcheckUtilities.CompressedUniPoly[](polys.length); - for (uint256 index = 0; index < polys.length; index++) { - compressed_polys[index] = SumcheckUtilities.CompressedUniPoly(polys[index].coeffs_except_linear_term); - } + SumcheckUtilities.SumcheckProof memory sumcheckProof = extract_sumcheck_proof(proof); if (enableLogging) { console.log("-----------compute_claim_sat_final_r_sat_primary------------"); console.log("CompressedUniPoly"); - for (uint256 index = 0; index < compressed_polys.length; index++) { + for (uint256 index = 0; index < sumcheckProof.compressed_polys.length; index++) { console.log(index); - for (uint256 i = 0; i < compressed_polys[index].coeffs_except_linear_term.length; i++) { - console.logBytes32(bytes32(compressed_polys[index].coeffs_except_linear_term[i])); + for (uint256 i = 0; i < sumcheckProof.compressed_polys[index].coeffs_except_linear_term.length; i++) { + console.logBytes32(bytes32(sumcheckProof.compressed_polys[index].coeffs_except_linear_term[i])); } } } // degreeBound is hardcoded to 3 in Rust return PrimarySumcheck.verify( - SumcheckUtilities.SumcheckProof(compressed_polys), - mulmod(coeffs[9], claim_inner, p_modulus), - log2(vk.S_comm.N), + sumcheckProof, + compute_sumcheck_claim(claim_inner, coeffs, p_modulus), + CommonUtilities.log2(vk.S_comm.N), 3, transcript ); } function compute_claim_sat_final_r_sat_secondary( - Abstractions.CompressedSnark calldata proof, - Abstractions.VerifierKey calldata vk, + Abstractions.RelaxedR1CSSNARK calldata proof, + Abstractions.VerifierKeyS2 calldata vk, KeccakTranscriptLib.KeccakTranscript memory transcript, uint256 claim_inner, uint256[] memory coeffs, - uint256 p_modulus + uint256 p_modulus, + bool enableLogging ) public returns (uint256, uint256[] memory, KeccakTranscriptLib.KeccakTranscript memory) { - // TODO: simplify convertions between abstractions - Abstractions.CompressedPolys[] memory polys = proof.f_W_snark_secondary.sc_sat.compressed_polys; - SumcheckUtilities.CompressedUniPoly[] memory compressed_polys = - new SumcheckUtilities.CompressedUniPoly[](polys.length); - for (uint256 index = 0; index < polys.length; index++) { - compressed_polys[index] = SumcheckUtilities.CompressedUniPoly(polys[index].coeffs_except_linear_term); + SumcheckUtilities.SumcheckProof memory sumcheckProof = extract_sumcheck_proof(proof); + + if (enableLogging) { + console.log("-----------compute_claim_sat_final_r_sat_secondary------------"); + console.log("CompressedUniPoly"); + for (uint256 index = 0; index < sumcheckProof.compressed_polys.length; index++) { + console.log(index); + for (uint256 i = 0; i < sumcheckProof.compressed_polys[index].coeffs_except_linear_term.length; i++) { + console.logBytes32(bytes32(sumcheckProof.compressed_polys[index].coeffs_except_linear_term[i])); + } + } } // degreeBound is hardcoded to 3 in Rust return SecondarySumcheck.verify( - SumcheckUtilities.SumcheckProof(compressed_polys), - mulmod(coeffs[9], claim_inner, p_modulus), - log2(vk.vk_secondary.S_comm.N), + sumcheckProof, + compute_sumcheck_claim(claim_inner, coeffs, p_modulus), + CommonUtilities.log2(vk.S_comm.N), 3, transcript ); @@ -293,7 +317,7 @@ library Step3Lib { transcript = KeccakTranscriptLib.absorb(transcript, label, Abstractions.toTranscriptBytes(claims_product_arr)); - uint256 num_rounds = log2(vk.S_comm.N); + uint256 num_rounds = CommonUtilities.log2(vk.S_comm.N); label[0] = 0x65; // Rust's b"e" uint256[] memory rand_eq = new uint256[](num_rounds); @@ -332,7 +356,7 @@ library Step3Lib { transcript = KeccakTranscriptLib.absorb(transcript, label, Abstractions.toTranscriptBytes(claims_product_arr)); - uint256 num_rounds = log2(vk.vk_secondary.S_comm.N); + uint256 num_rounds = CommonUtilities.log2(vk.vk_secondary.S_comm.N); label[0] = 0x65; // Rust's b"e" uint256[] memory rand_eq = new uint256[](num_rounds); @@ -595,7 +619,7 @@ library Step3Lib { label = new uint8[](1); // Rust's b"t" label[0] = 0x74; - uint256 num_rounds_sat = log2(vk.S_comm.N); + uint256 num_rounds_sat = CommonUtilities.log2(vk.S_comm.N); uint256[] memory tau = new uint256[](num_rounds_sat); @@ -776,35 +800,4 @@ library Step3Lib { addmod(U1.u, r, Vesta.P_MOD) ); } - - function log2(uint256 x) private pure returns (uint256 y) { - assembly { - let arg := x - x := sub(x, 1) - x := or(x, div(x, 0x02)) - x := or(x, div(x, 0x04)) - x := or(x, div(x, 0x10)) - x := or(x, div(x, 0x100)) - x := or(x, div(x, 0x10000)) - x := or(x, div(x, 0x100000000)) - x := or(x, div(x, 0x10000000000000000)) - x := or(x, div(x, 0x100000000000000000000000000000000)) - x := add(x, 1) - let m := mload(0x40) - mstore(m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd) - mstore(add(m, 0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe) - mstore(add(m, 0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616) - mstore(add(m, 0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff) - mstore(add(m, 0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e) - mstore(add(m, 0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707) - mstore(add(m, 0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606) - mstore(add(m, 0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100) - mstore(0x40, add(m, 0x100)) - let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff - let shift := 0x100000000000000000000000000000000000000000000000000000000000000 - let a := div(mul(x, magic), shift) - y := div(mload(add(m, sub(255, a))), shift) - y := add(y, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000))) - } - } } diff --git a/src/verifier/Step4.sol b/src/verifier/Step4.sol index 20d7298..d144ce5 100644 --- a/src/verifier/Step4.sol +++ b/src/verifier/Step4.sol @@ -7,7 +7,7 @@ import "src/blocks/pasta/Vesta.sol"; import "src/NovaVerifierAbstractions.sol"; library Step4Lib { - function verify(Abstractions.CompressedSnark calldata proof) public view returns (bool) { + function verify(Abstractions.CompressedSnark calldata proof) public pure returns (bool) { if (!verifyInner(proof.r_W_snark_primary, Vesta.P_MOD)) { return false; } else if (!verifyInner(proof.f_W_snark_secondary, Pallas.P_MOD)) { @@ -16,7 +16,7 @@ library Step4Lib { return true; } - function verifyInner(Abstractions.RelaxedR1CSSNARK calldata proof, uint256 modulus) private view returns (bool) { + function verifyInner(Abstractions.RelaxedR1CSSNARK calldata proof, uint256 modulus) private pure returns (bool) { // row uint256 left = mulmod(proof.claims_product_arr[0], proof.claims_product_arr[2], modulus); uint256 right = mulmod(proof.claims_product_arr[1], proof.claims_product_arr[3], modulus); diff --git a/src/verifier/Step5.sol b/src/verifier/Step5.sol index 3f5008b..1904327 100644 --- a/src/verifier/Step5.sol +++ b/src/verifier/Step5.sol @@ -16,7 +16,7 @@ library Step5Lib { uint256 claim_read_expected_row, uint256 claim_write_expected_row, uint256 claim_audit_expected_row - ) public returns (bool) { + ) public pure returns (bool) { if (claim_init_expected_row != proof.eval_input_arr[0]) { return false; } @@ -40,7 +40,7 @@ library Step5Lib { uint256 ts, uint256 modulus, function (uint256) returns (uint256) negate - ) private returns (uint256) { + ) internal returns (uint256) { uint256 result = val; uint256 tmp = ts; uint256 minus_gamma2 = negate(gamma2); @@ -106,7 +106,7 @@ library Step5Lib { return (claim_read, claim_write); } - function compute_r_prod(uint256 c, uint256[] memory r_sat) public returns (uint256[] memory) { + function compute_r_prod(uint256 c, uint256[] memory r_sat) public pure returns (uint256[] memory) { uint256[] memory rand_ext = new uint256[](r_sat.length + 1); for (uint256 index = 0; index < r_sat.length; index++) { rand_ext[index] = r_sat[index]; @@ -122,7 +122,7 @@ library Step5Lib { return r_prod; } - function compute_c_inner(Abstractions.RelaxedR1CSSNARK storage proof) private returns (uint8[] memory) { + function compute_c_inner(Abstractions.RelaxedR1CSSNARK storage proof) private view returns (uint8[] memory) { uint256 index = 0; uint256[] memory eval_vec = new uint256[](9 + proof.eval_left_arr.length + proof.eval_right_arr.length + proof.eval_output_arr.length); @@ -174,7 +174,7 @@ library Step5Lib { function compute_c_primary( Abstractions.RelaxedR1CSSNARK storage proof, KeccakTranscriptLib.KeccakTranscript memory transcript - ) public returns (KeccakTranscriptLib.KeccakTranscript memory, uint256) { + ) public view returns (KeccakTranscriptLib.KeccakTranscript memory, uint256) { uint8[] memory input = compute_c_inner(proof); uint8[] memory label = new uint8[](1); @@ -194,7 +194,7 @@ library Step5Lib { function compute_c_secondary( Abstractions.RelaxedR1CSSNARK storage proof, KeccakTranscriptLib.KeccakTranscript memory transcript - ) public returns (KeccakTranscriptLib.KeccakTranscript memory, uint256) { + ) public view returns (KeccakTranscriptLib.KeccakTranscript memory, uint256) { uint8[] memory input = compute_c_inner(proof); uint8[] memory label = new uint8[](1); diff --git a/src/verifier/Step6.sol b/src/verifier/Step6.sol new file mode 100644 index 0000000..faf2efb --- /dev/null +++ b/src/verifier/Step6.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import "@std/Test.sol"; +import "src/verifier/Step5.sol"; +import "src/blocks/IdentityPolynomial.sol"; +import "src/blocks/SparsePolynomial.sol"; +import "src/NovaVerifierAbstractions.sol"; + +library Step6Lib { + function finalVerification( + Abstractions.RelaxedR1CSSNARK calldata proof, + uint256 claim_init_expected_col, + uint256 claim_read_expected_col, + uint256 claim_write_expected_col, + uint256 claim_audit_expected_col + ) public pure returns (bool) { + if (claim_init_expected_col != proof.eval_input_arr[4]) { + return false; + } + + if (claim_read_expected_col != proof.eval_input_arr[5]) { + return false; + } + + if (claim_write_expected_col != proof.eval_input_arr[6]) { + return false; + } + + if (claim_audit_expected_col != proof.eval_input_arr[7]) { + return false; + } + + return true; + } + + function compute_claims_init_audit( + Abstractions.RelaxedR1CSSNARK storage proof, + uint256 gamma1, + uint256 gamma2, + uint256 eval_Z, + uint256[] memory r_prod, + uint256 modulus, + function (uint256) returns (uint256) negate + ) internal returns (uint256, uint256) { + return ( + Step5Lib.hash_func( + gamma1, gamma2, IdentityPolynomialLib.evaluate(r_prod, modulus), eval_Z, 0, modulus, negate + ), + Step5Lib.hash_func( + gamma1, + gamma2, + IdentityPolynomialLib.evaluate(r_prod, modulus), + eval_Z, + proof.eval_col_audit_ts, + modulus, + negate + ) + ); + } + + function compute_claims_read_write( + Abstractions.RelaxedR1CSSNARK storage proof, + uint256 gamma1, + uint256 gamma2, + uint256 modulus, + function (uint256) returns (uint256) negateBase + ) internal returns (uint256, uint256) { + uint256 ts_write = addmod(proof.eval_col_read_ts, 1, modulus); + return ( + Step5Lib.hash_func( + gamma1, gamma2, proof.eval_col, proof.eval_E_col_at_r_prod, proof.eval_col_read_ts, modulus, negateBase + ), + Step5Lib.hash_func( + gamma1, gamma2, proof.eval_col, proof.eval_E_col_at_r_prod, ts_write, modulus, negateBase + ) + ); + } + + function compute_eval_X( + uint256 num_vars, + uint256[] memory r_prod_unpad, + uint256[] memory U_X, + uint256 U_u, + uint256 modulus, + function (uint256) returns (uint256) negateBase + ) internal returns (uint256) { + uint256[] memory r_prod_unpad_no_zero_element = new uint256[](r_prod_unpad.length - 1); + uint256 index = 0; + for (index = 0; index < r_prod_unpad_no_zero_element.length; index++) { + r_prod_unpad_no_zero_element[index] = r_prod_unpad[index + 1]; + } + + index = 0; + SparsePolynomialLib.Z[] memory poly_X = new SparsePolynomialLib.Z[](U_X.length + 1); + poly_X[index] = SparsePolynomialLib.Z(index, U_u); + index++; + + for (uint256 i = 0; i < U_X.length; i++) { + poly_X[index] = SparsePolynomialLib.Z(index, U_X[i]); + index++; + } + + uint256 actual = SparsePolynomialLib.evaluate( + CommonUtilities.log2(num_vars), poly_X, r_prod_unpad_no_zero_element, modulus, negateBase + ); + + return actual; + } + + function compute_factor( + uint256 vk_s_comm_N, + uint256 num_vars, + uint256[] memory r_prod, + uint256 modulus, + function (uint256) returns (uint256) negateBase + ) internal returns (uint256, uint256[] memory) { + if (vk_s_comm_N < num_vars) { + console.log("[Step6::compute_factor] vk_s_comm_N < num_vars"); + revert(); + } + + uint256 l = CommonUtilities.log2(vk_s_comm_N) - CommonUtilities.log2(2 * num_vars); + + if (l > r_prod.length) { + console.log("[Step6::compute_factor] l > r_prod.length"); + revert(); + } + + uint256 factor = 1; + + uint256 tmp; + for (uint256 index = 0; index < l; index++) { + tmp = negateBase(r_prod[index]); + tmp = addmod(tmp, 1, modulus); + factor = mulmod(factor, tmp, modulus); + } + + uint256[] memory r_prod_unpad = new uint256[](r_prod.length - l); + for (uint256 index = 0; index < r_prod_unpad.length; index++) { + r_prod_unpad[index] = r_prod[index + l]; + } + + return (factor, r_prod_unpad); + } + + function compute_eval_Z( + Abstractions.RelaxedR1CSSNARK storage proof, + uint256[] memory U_X, + uint256 U_u, + uint256 vk_s_comm_N, + uint256 num_vars, + uint256[] memory r_prod, + uint256 modulus, + function (uint256) returns (uint256) negateBase + ) internal returns (uint256) { + uint256 self_eval_W = proof.eval_W; + + (uint256 factor, uint256[] memory r_prod_unpad) = + compute_factor(vk_s_comm_N, num_vars, r_prod, modulus, negateBase); + + uint256 eval_X = compute_eval_X(num_vars, r_prod_unpad, U_X, U_u, modulus, negateBase); + + uint256 result; + uint256 r_prod_unpad_0 = r_prod_unpad[0]; + uint256 tmp = negateBase(r_prod_unpad_0); + assembly { + tmp := addmod(tmp, 1, modulus) + tmp := mulmod(tmp, self_eval_W, modulus) + result := mulmod(r_prod_unpad_0, eval_X, modulus) + result := addmod(result, tmp, modulus) + result := mulmod(result, factor, modulus) + } + return result; + } +} diff --git a/test/pp-spartan-step-5.t.sol b/test/pp-spartan-step-5.t.sol index af2f87d..8f50c90 100644 --- a/test/pp-spartan-step-5.t.sol +++ b/test/pp-spartan-step-5.t.sol @@ -10,6 +10,7 @@ import "src/NovaVerifierAbstractions.sol"; contract PpSpartanStep5Computations is Test { function loadDataForFinalVerification() private + pure returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) { uint256 self_eval_input_arr_0 = 0x259ca7141dabcc8b8fe1f99033c3864ecdda5ce134960487fb6ad829750c178b; @@ -39,7 +40,7 @@ contract PpSpartanStep5Computations is Test { uint256 claim_read_expected_row, uint256 claim_write_expected_row, uint256 claim_audit_expected_row - ) private returns (bool) { + ) private pure returns (bool) { uint256 self_eval_input_arr_0; uint256 self_eval_input_arr_1; uint256 self_eval_input_arr_2; @@ -66,7 +67,7 @@ contract PpSpartanStep5Computations is Test { return true; } - function testFinalVerification() public { + function testFinalVerification() public pure { // primary uint256 claim_init_expected_row; @@ -86,6 +87,7 @@ contract PpSpartanStep5Computations is Test { function loadDataForClaimsInitAudit() private + pure returns (uint256[] memory, uint256[] memory, uint256, uint256, uint256) { uint256[] memory r_prod = new uint256[](17); @@ -214,7 +216,7 @@ contract PpSpartanStep5Computations is Test { return (claim_read, claim_write); } - function loadDataForClaimsReadWrite() private returns (uint256, uint256, uint256, uint256, uint256) { + function loadDataForClaimsReadWrite() private pure returns (uint256, uint256, uint256, uint256, uint256) { uint256 eval_row = 0x01c4e19f9061888370440ee422429adaad35d48103b8feacab8aa189f35307a9; uint256 eval_E_row_at_r_prod = 0x33a9e536648e6e70892b52cb92f77b3fba23983fe3f051b0167b883906ef8e2c; uint256 eval_row_read_ts = 0x1f028067c1a3091aa323ab801432abdabe174d2a7182ece2a4adf33dbaec9dcb; @@ -245,7 +247,7 @@ contract PpSpartanStep5Computations is Test { assertEq(claim_write_expected, claim_write); } - function loadDataForRProd() private returns (uint256, uint256[] memory, uint256[] memory) { + function loadDataForRProd() private pure returns (uint256, uint256[] memory, uint256[] memory) { uint256 c = 0x1741b54a11d0633c0349b0e317ced512a59ef40b772fbe94415e42af34a25c99; uint256[] memory r_sat = new uint256[](17); r_sat[0] = 0x066b998f211c11d58f5c4ce0eb59a7ba543bdab2c99b5061c097723eb0ed8ff9; @@ -288,7 +290,7 @@ contract PpSpartanStep5Computations is Test { return (c, r_sat, r_prod_expected); } - function compute_r_prod(uint256 c, uint256[] memory r_sat) private returns (uint256[] memory) { + function compute_r_prod(uint256 c, uint256[] memory r_sat) private pure returns (uint256[] memory) { uint256[] memory rand_ext = new uint256[](r_sat.length + 1); for (uint256 index = 0; index < r_sat.length; index++) { rand_ext[index] = r_sat[index]; @@ -315,7 +317,7 @@ contract PpSpartanStep5Computations is Test { } } - function loadTranscript() private returns (KeccakTranscriptLib.KeccakTranscript memory) { + function loadTranscript() private pure returns (KeccakTranscriptLib.KeccakTranscript memory) { uint16 rounds = 55; uint8[] memory state = new uint8[](64); state[0] = 0xf9; @@ -390,6 +392,7 @@ contract PpSpartanStep5Computations is Test { function loadDataForC() private + pure returns ( uint256[] memory, uint256[] memory, @@ -454,7 +457,7 @@ contract PpSpartanStep5Computations is Test { uint256[] memory eval_left_arr, uint256[] memory eval_right_arr, uint256[] memory eval_output_arr - ) private returns (uint256[] memory) { + ) private pure returns (uint256[] memory) { uint256 index = 0; uint256[] memory eval_vec = new uint256[](eval_left_arr.length + eval_right_arr.length + eval_output_arr.length + eval_A_B_C_z.length + evals_E.length + evals_val.length); diff --git a/test/pp-spartan-step-6.t.sol b/test/pp-spartan-step-6.t.sol new file mode 100644 index 0000000..b6f79b9 --- /dev/null +++ b/test/pp-spartan-step-6.t.sol @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +import "@std/Test.sol"; +import "src/blocks/pasta/Vesta.sol"; +import "src/blocks/pasta/Pallas.sol"; +import "src/blocks/SparsePolynomial.sol"; +import "src/blocks/IdentityPolynomial.sol"; +import "src/Utilities.sol"; + +contract PpSpartanStep6Computations is Test { + function loadDataForFinalVerification() + private + pure + returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) + { + uint256 self_eval_input_arr_4 = 0x32e163ca55c8cbcd8832b9e62eb4615f8e0303d3f0972690bf9711a8f6f2638c; + uint256 self_eval_input_arr_5 = 0x1df44137760761fc7024d964fb569952aacfcf9f66263b91a744023fa9e627d8; + uint256 self_eval_input_arr_6 = 0x39defd5f9c03ad878eae23a6d25986c6c1385ec6b9c30c37e34bb794c3ee90ae; + uint256 self_eval_input_arr_7 = 0x2201d18ffbf44a7f25c8379b6c6a58c39184a82aa81c8744a7f01aabefe7f5eb; + + uint256 claim_init_expected_col = 0x32e163ca55c8cbcd8832b9e62eb4615f8e0303d3f0972690bf9711a8f6f2638c; + uint256 claim_read_expected_col = 0x1df44137760761fc7024d964fb569952aacfcf9f66263b91a744023fa9e627d8; + uint256 claim_write_expected_col = 0x39defd5f9c03ad878eae23a6d25986c6c1385ec6b9c30c37e34bb794c3ee90ae; + uint256 claim_audit_expected_col = 0x2201d18ffbf44a7f25c8379b6c6a58c39184a82aa81c8744a7f01aabefe7f5eb; + + return ( + self_eval_input_arr_4, + self_eval_input_arr_5, + self_eval_input_arr_6, + self_eval_input_arr_7, + claim_init_expected_col, + claim_read_expected_col, + claim_write_expected_col, + claim_audit_expected_col + ); + } + + function finalVerification( + uint256 claim_init_expected_col, + uint256 claim_read_expected_col, + uint256 claim_write_expected_col, + uint256 claim_audit_expected_col + ) private pure returns (bool) { + uint256 self_eval_input_arr_4; + uint256 self_eval_input_arr_5; + uint256 self_eval_input_arr_6; + uint256 self_eval_input_arr_7; + (self_eval_input_arr_4, self_eval_input_arr_5, self_eval_input_arr_6, self_eval_input_arr_7,,,,) = + loadDataForFinalVerification(); + + if (claim_init_expected_col != self_eval_input_arr_4) { + return false; + } + + if (claim_read_expected_col != self_eval_input_arr_5) { + return false; + } + + if (claim_write_expected_col != self_eval_input_arr_6) { + return false; + } + + if (claim_audit_expected_col != self_eval_input_arr_7) { + return false; + } + + return true; + } + + function testFinalVerification() public pure { + // primary + + uint256 claim_init_expected_col; + uint256 claim_read_expected_col; + uint256 claim_write_expected_col; + uint256 claim_audit_expected_col; + + (,,,, claim_init_expected_col, claim_read_expected_col, claim_write_expected_col, claim_audit_expected_col) = + loadDataForFinalVerification(); + + assert( + finalVerification( + claim_init_expected_col, claim_read_expected_col, claim_write_expected_col, claim_audit_expected_col + ) + ); + } + + function loadDataForClaimsInitAudit() private pure returns (uint256[] memory, uint256, uint256, uint256, uint256) { + uint256[] memory r_prod = new uint256[](17); + r_prod[0] = 0x1e525e8eb5732494ab1aebe43df1d2a0150badb04db05681409c612429cea8ac; + r_prod[1] = 0x317b05d9d1941be2116f250a8aad1932d009cec690d12ef463fe64c5efadc978; + r_prod[2] = 0x13493a5dc4e2513470e1749fdb37b41e3836364d77d7eb8b5a81b985bfe7333a; + r_prod[3] = 0x05499a9b11713b3371978cf62676fc88bbd1784df341575d88c183fe7d2baec2; + r_prod[4] = 0x304fd43c6453b62cfe98bc726e458208edf3754b58a1b96b48baedb08dc231b6; + r_prod[5] = 0x2d5ce24c1355a2428de1d5411ecebd98b1328b5b6f87dcc9ecb573252d6cf30d; + r_prod[6] = 0x2d6762046fc5ca62b436c758321b1844ac5cf096e30085cb81ddd076138d7163; + r_prod[7] = 0x3ec3a1be092aa81390fb585c46fd3774b20febd739904f20c99ab2c9d0f3ef46; + r_prod[8] = 0x382b206460e5706009787007b6e484e80423783762ebac703d3cbb9c2615e7b2; + r_prod[9] = 0x1c9118d02c7792a8728fa7a879687962ae5a1b5aa9942420d239ada6cef57149; + r_prod[10] = 0x39672312a3af1dadc7dd77703cef7487ae0f27634ce37faba6e81f0b7eae3d25; + r_prod[11] = 0x0ec9a8b069eed91e089a03c0f47615fe04742b8c1159a10dde4129b71fc65687; + r_prod[12] = 0x3998456c5125913b2489869938b5b0d98e7f5c87327af98b9dc619fe54fd26c1; + r_prod[13] = 0x08a01a276934627dad600b53978bd5d64de6090ecb2bef2b73c3d6e346e5c096; + r_prod[14] = 0x394edaa7014bdeed61ad362a7d9ec5877ad82777dd131489152c96b848a05d78; + r_prod[15] = 0x0ede18a94d3bdf5f9ee7a7ae19c34315d98847bc4086c9d81f5264b1e127ec78; + r_prod[16] = 0x1741b54a11d0633c0349b0e317ced512a59ef40b772fbe94415e42af34a25c99; + + uint256 gamma1 = 0x208210b1790f70ee67ac7d528b3a4916f9779bc476ac48421c3b0d5500a59b34; + uint256 gamma2 = 0x380407a49ddc0c535ec44bf588822f1b7bf5234336e228cc0f62e801ba9f88ce; + uint256 self_eval_col_audit_ts = 0x0a9989c75a4a4aabcd6e8c66f0c035513bac66ac12fcbeaf1338712c2d1fde38; + uint256 eval_Z = 0x0dabf3857ebe01c6e96ed15174352d9cd4a4774fe5e0d9e73464e4feee8176a5; + + return (r_prod, self_eval_col_audit_ts, gamma1, gamma2, eval_Z); + } + + function hash_func( + uint256 gamma1, + uint256 gamma2, + uint256 addr, + uint256 val, + uint256 ts, + uint256 modulus, + function (uint256) returns (uint256) negate + ) private returns (uint256) { + uint256 result = val; + uint256 tmp = ts; + uint256 minus_gamma2 = negate(gamma2); + assembly { + tmp := mulmod(tmp, gamma1, modulus) + tmp := mulmod(tmp, gamma1, modulus) + + result := mulmod(result, gamma1, modulus) + result := addmod(result, tmp, modulus) + result := addmod(result, addr, modulus) + result := addmod(result, minus_gamma2, modulus) + } + + return result; + } + + function compute_claims_init_audit( + uint256 gamma1, + uint256 gamma2, + uint256 eval_col_audit_ts, + uint256 eval_Z, + uint256[] memory r_prod, + uint256 modulus, + function (uint256) returns (uint256) negate + ) private returns (uint256, uint256) { + uint256 addr = IdentityPolynomialLib.evaluate(r_prod, modulus); + uint256 val = eval_Z; + + uint256 claim_init = hash_func(gamma1, gamma2, addr, val, 0, modulus, negate); + uint256 claim_audit = hash_func(gamma1, gamma2, addr, val, eval_col_audit_ts, modulus, negate); + + return (claim_init, claim_audit); + } + + function test_compute_claims_init_audit() public { + // primary + uint256 claim_init_expected; + uint256 claim_audit_expected; + (,,,, claim_init_expected,,, claim_audit_expected) = loadDataForFinalVerification(); + + uint256[] memory r_prod; + uint256 eval_col_audit_ts; + uint256 gamma1; + uint256 gamma2; + uint256 eval_Z; + (r_prod, eval_col_audit_ts, gamma1, gamma2, eval_Z) = loadDataForClaimsInitAudit(); + + (uint256 claim_init_actual, uint256 claim_audit_actual) = + compute_claims_init_audit(gamma1, gamma2, eval_col_audit_ts, eval_Z, r_prod, Vesta.P_MOD, Vesta.negateBase); + + assertEq(claim_audit_actual, claim_audit_expected); + assertEq(claim_init_actual, claim_init_expected); + } + + function compute_claims_read_write( + uint256 gamma1, + uint256 gamma2, + uint256 eval_col, + uint256 eval_E_col_at_r_prod, + uint256 eval_col_read_ts, + uint256 modulus, + function (uint256) returns (uint256) negateBase + ) private returns (uint256, uint256) { + uint256 claim_read = + hash_func(gamma1, gamma2, eval_col, eval_E_col_at_r_prod, eval_col_read_ts, modulus, negateBase); + + uint256 ts_write = addmod(eval_col_read_ts, 1, modulus); + uint256 claim_write = hash_func(gamma1, gamma2, eval_col, eval_E_col_at_r_prod, ts_write, modulus, negateBase); + + return (claim_read, claim_write); + } + + function loadDataForClaimsReadWrite() private pure returns (uint256, uint256, uint256, uint256, uint256) { + uint256 eval_col = 0x02a59bba81c8b01754912164ee6d44b2f0dfceffb49026b56d381b2c8ad90a47; + uint256 eval_E_col_at_r_prod = 0x2bd1d000b6fc3a97f16fd0f453737d90bfac43998c396782ddc0f152f70d53af; + uint256 eval_col_read_ts = 0x3cca4aecdecd11b9d6839796f97b5fb638fbaf87906a2567c1e410d9ce01ef66; + uint256 gamma1 = 0x208210b1790f70ee67ac7d528b3a4916f9779bc476ac48421c3b0d5500a59b34; + uint256 gamma2 = 0x380407a49ddc0c535ec44bf588822f1b7bf5234336e228cc0f62e801ba9f88ce; + + return (eval_col, eval_E_col_at_r_prod, eval_col_read_ts, gamma1, gamma2); + } + + function test_compute_claims_read_write() public { + // primary + uint256 claim_read_expected; + uint256 claim_write_expected; + (,,,,, claim_read_expected, claim_write_expected,) = loadDataForFinalVerification(); + + uint256 eval_col; + uint256 eval_E_col_at_r_prod; + uint256 eval_col_read_ts; + uint256 gamma1; + uint256 gamma2; + (eval_col, eval_E_col_at_r_prod, eval_col_read_ts, gamma1, gamma2) = loadDataForClaimsReadWrite(); + + (uint256 claim_read, uint256 claim_write) = compute_claims_read_write( + gamma1, gamma2, eval_col, eval_E_col_at_r_prod, eval_col_read_ts, Vesta.P_MOD, Vesta.negateBase + ); + + assertEq(claim_read_expected, claim_read); + assertEq(claim_write_expected, claim_write); + } + + function compute_eval_Z( + uint256 factor, + uint256 r_prod_unpad_0, + uint256 self_eval_W, + uint256 eval_X, + uint256 modulus, + function (uint256) returns (uint256) negateBase + ) private returns (uint256) { + uint256 result; + uint256 tmp = negateBase(r_prod_unpad_0); + assembly { + tmp := addmod(tmp, 1, modulus) + tmp := mulmod(tmp, self_eval_W, modulus) + result := mulmod(r_prod_unpad_0, eval_X, modulus) + result := addmod(result, tmp, modulus) + result := mulmod(result, factor, modulus) + } + return result; + } + + function compute_factor(uint256 vk_s_comm_N, uint256 num_vars) private pure returns (uint256, uint256[] memory) { + require(vk_s_comm_N >= num_vars, "[Step6::compute_factor] vk_s_comm_N < num_vars"); + + uint256[] memory r_prod_expected = new uint256[](17); + r_prod_expected[0] = 0x1e525e8eb5732494ab1aebe43df1d2a0150badb04db05681409c612429cea8ac; + r_prod_expected[1] = 0x317b05d9d1941be2116f250a8aad1932d009cec690d12ef463fe64c5efadc978; + r_prod_expected[2] = 0x13493a5dc4e2513470e1749fdb37b41e3836364d77d7eb8b5a81b985bfe7333a; + r_prod_expected[3] = 0x05499a9b11713b3371978cf62676fc88bbd1784df341575d88c183fe7d2baec2; + r_prod_expected[4] = 0x304fd43c6453b62cfe98bc726e458208edf3754b58a1b96b48baedb08dc231b6; + r_prod_expected[5] = 0x2d5ce24c1355a2428de1d5411ecebd98b1328b5b6f87dcc9ecb573252d6cf30d; + r_prod_expected[6] = 0x2d6762046fc5ca62b436c758321b1844ac5cf096e30085cb81ddd076138d7163; + r_prod_expected[7] = 0x3ec3a1be092aa81390fb585c46fd3774b20febd739904f20c99ab2c9d0f3ef46; + r_prod_expected[8] = 0x382b206460e5706009787007b6e484e80423783762ebac703d3cbb9c2615e7b2; + r_prod_expected[9] = 0x1c9118d02c7792a8728fa7a879687962ae5a1b5aa9942420d239ada6cef57149; + r_prod_expected[10] = 0x39672312a3af1dadc7dd77703cef7487ae0f27634ce37faba6e81f0b7eae3d25; + r_prod_expected[11] = 0x0ec9a8b069eed91e089a03c0f47615fe04742b8c1159a10dde4129b71fc65687; + r_prod_expected[12] = 0x3998456c5125913b2489869938b5b0d98e7f5c87327af98b9dc619fe54fd26c1; + r_prod_expected[13] = 0x08a01a276934627dad600b53978bd5d64de6090ecb2bef2b73c3d6e346e5c096; + r_prod_expected[14] = 0x394edaa7014bdeed61ad362a7d9ec5877ad82777dd131489152c96b848a05d78; + r_prod_expected[15] = 0x0ede18a94d3bdf5f9ee7a7ae19c34315d98847bc4086c9d81f5264b1e127ec78; + r_prod_expected[16] = 0x1741b54a11d0633c0349b0e317ced512a59ef40b772fbe94415e42af34a25c99; + + uint256 l = CommonUtilities.log2(vk_s_comm_N) - CommonUtilities.log2(2 * num_vars); + + require(l <= r_prod_expected.length, "[Step6::compute_factor] l > r_prod_expected.length"); + + uint256 factor = 1; + + uint256 tmp; + for (uint256 index = 0; index < l; index++) { + tmp = Vesta.negateBase(r_prod_expected[index]); + tmp = addmod(tmp, 1, Vesta.P_MOD); + factor = mulmod(factor, tmp, Vesta.P_MOD); + } + + uint256[] memory r_prod_unpad = new uint256[](r_prod_expected.length - l); + for (uint256 index = 0; index < r_prod_unpad.length; index++) { + r_prod_unpad[index] = r_prod_expected[index + l]; + } + + return (factor, r_prod_unpad); + } + + function compute_eval_X(uint256 num_vars, uint256[] memory r_prod_unpad) private returns (uint256) { + uint256 U_u = 0x00000000000000000000000000000000e0cd65f84e44c9ec91e2884db641d086; + uint256[] memory U_X = new uint256[](2); + U_X[0] = 0x1008e89ef900296673cb9c082667db6076520e3823832702a98d82b0abc89337; + U_X[1] = 0x09426e0ffdfcfabc83cebf36d6ef04f69dc55c775e11d46e10c2d2c17a33d909; + + uint256 index = 0; + uint256[] memory r_prod_unpad_no_zero_element = new uint256[](r_prod_unpad.length - 1); + for (index = 0; index < r_prod_unpad_no_zero_element.length; index++) { + r_prod_unpad_no_zero_element[index] = r_prod_unpad[index + 1]; + } + + index = 0; + SparsePolynomialLib.Z[] memory poly_X = new SparsePolynomialLib.Z[](U_X.length + 1); + poly_X[index] = SparsePolynomialLib.Z(index, U_u); + index++; + + for (uint256 i = 0; i < U_X.length; i++) { + poly_X[index] = SparsePolynomialLib.Z(index, U_X[i]); + index++; + } + + uint256 actual = SparsePolynomialLib.evaluate( + CommonUtilities.log2(num_vars), poly_X, r_prod_unpad_no_zero_element, Vesta.P_MOD, Vesta.negateBase + ); + + return actual; + } + + function test_compute_eval_Z() public { + uint256 self_eval_W = 0x17938b6eba9ed44f2cc8f93d2b529b20c957e8f6e3a043300e304930614b564e; + uint256 vk_s_comm_N = 131072; + uint256 num_vars = 16384; + + (uint256 factor, uint256[] memory r_prod_unpad) = compute_factor(vk_s_comm_N, num_vars); + + uint256 eval_X = compute_eval_X(num_vars, r_prod_unpad); + + uint256 actual = compute_eval_Z(factor, r_prod_unpad[0], self_eval_W, eval_X, Vesta.P_MOD, Vesta.negateBase); + + uint256 expected = 0x0dabf3857ebe01c6e96ed15174352d9cd4a4774fe5e0d9e73464e4feee8176a5; + assertEq(expected, actual); + } +}