From 0b0513f672327e1f3c9b7cf2d9c7e609df92b488 Mon Sep 17 00:00:00 2001 From: maramihali Date: Fri, 10 Jan 2025 15:23:21 +0000 Subject: [PATCH 1/4] refactor solidity --- barretenberg/acir_tests/sol-test/src/index.js | 3 +- .../dsl/acir_proofs/honk_contract.hpp | 356 ++++++++---------- .../sol/src/honk/BaseHonkVerifier.sol | 33 +- barretenberg/sol/src/honk/HonkTypes.sol | 11 + barretenberg/sol/src/honk/Relations.sol | 68 ++-- barretenberg/sol/src/honk/Transcript.sol | 206 +++++----- barretenberg/sol/src/honk/utils.sol | 17 + 7 files changed, 320 insertions(+), 374 deletions(-) diff --git a/barretenberg/acir_tests/sol-test/src/index.js b/barretenberg/acir_tests/sol-test/src/index.js index ca402b061828..b1c28cd6c183 100644 --- a/barretenberg/acir_tests/sol-test/src/index.js +++ b/barretenberg/acir_tests/sol-test/src/index.js @@ -94,9 +94,10 @@ if (!testingHonk) { } var output = JSON.parse(solc.compile(JSON.stringify(compilationInput))); -if (output.errors.some((e) => e.type == "Error")) { +if (output.errors.some((e) => e.severity == "error")) { throw new Error(JSON.stringify(output.errors, null, 2)); } + const contract = output.contracts["Test.sol"]["Test"]; const bytecode = contract.evm.bytecode.object; const abi = contract.abi; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 98c352bcb32b..070cf069eaf7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -254,6 +254,18 @@ library Honk { G1Point lagrangeLast; } + struct RelationParameters { + // challenges + Fr eta; + Fr etaTwo; + Fr etaThree; + Fr beta; + Fr gamma; + // derived + Fr publicInputsDelta; + } + + struct Proof { uint256 circuitSize; uint256 publicInputsSize; @@ -280,36 +292,31 @@ library Honk { } } - // Transcript library to generate fiat shamir challenges struct Transcript { - Fr eta; - Fr etaTwo; - Fr etaThree; - Fr beta; - Fr gamma; + // Oink + Honk.RelationParameters relationParameters; Fr[NUMBER_OF_ALPHAS] alphas; Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges; + // Sumcheck Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges; - // Shplemini + // Gemini Fr rho; Fr geminiR; + // Shplonk Fr shplonkNu; Fr shplonkZ; - // Derived - Fr publicInputsDelta; } library TranscriptLib { function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) internal - pure + view returns (Transcript memory t) { Fr previousChallenge; - (t.eta, t.etaTwo, t.etaThree, previousChallenge) = generateEtaChallenge(proof, publicInputs, publicInputsSize); - - (t.beta, t.gamma, previousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + (t.relationParameters, previousChallenge) = + generateRelationParameters(proof, publicInputs, publicInputsSize, previousChallenge); (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); @@ -336,6 +343,65 @@ library TranscriptLib { second = FrLib.fromBytes32(bytes32(hi)); } + function generateRelationParameters( + Honk.Proof memory proof, + bytes32[] calldata publicInputs, + uint256 publicInputsSize, + Fr previousChallenge + ) internal view returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = + generateEtaChallenge(proof, publicInputs, publicInputsSize); + + (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + + // Derive public input delta + rp.publicInputsDelta = computePublicInputDelta( + publicInputs, publicInputsSize, rp.beta, rp.gamma, proof.circuitSize, proof.publicInputsOffset + ); + } + + function computePublicInputDelta( + bytes32[] memory publicInputs, + uint256 publicInputsSize, + Fr beta, + Fr gamma, + uint256 circuitSize, + uint256 offset + ) internal view returns (Fr publicInputDelta) { + Fr numerator = Fr.wrap(1); + Fr denominator = Fr.wrap(1); + + Fr numeratorAcc = gamma + (beta * FrLib.from(circuitSize + offset)); + Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); + + { + for (uint256 i = 0; i < publicInputsSize; i++) { + Fr pubInput = FrLib.fromBytes32(publicInputs[i]); + + numerator = numerator * (numeratorAcc + pubInput); + denominator = denominator * (denominatorAcc + pubInput); + + numeratorAcc = numeratorAcc + beta; + denominatorAcc = denominatorAcc - beta; + } + } + + // Fr delta = numerator / denominator; // TOOO: batch invert later? + publicInputDelta = FrLib.div(numerator, denominator); + } + + function generateChallengeRelationParameters( + Honk.Proof memory proof, + bytes32[] calldata publicInputs, + uint256 publicInputsSize, + Fr previousChallenge + ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = + generateEtaChallenge(proof, publicInputs, publicInputsSize); + + (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + } + function generateEtaChallenge(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) internal pure @@ -449,6 +515,7 @@ library TranscriptLib { Fr[BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; univariateChal[0] = prevChallenge; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1098): memcpy for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; } @@ -467,6 +534,7 @@ library TranscriptLib { Fr[NUMBER_OF_ENTITIES + 1] memory rhoChallengeElements; rhoChallengeElements[0] = prevChallenge; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1098): memcpy for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { rhoChallengeElements[i + 1] = proof.sumcheckEvaluations[i]; } @@ -531,152 +599,89 @@ library TranscriptLib { (shplonkZ, unused) = splitChallenge(nextPreviousChallenge); } - function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory) { - Honk.Proof memory p; - + // TODO: mod q proof points + // TODO: Preprocess all of the memory locations + // TODO: Adjust proof point serde away from poseidon forced field elements + // TODO: move this back to probably each instance to avoid dynamic init of arrays in the Transcript Lib + function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) { // Metadata p.circuitSize = uint256(bytes32(proof[0x00:0x20])); p.publicInputsSize = uint256(bytes32(proof[0x20:0x40])); p.publicInputsOffset = uint256(bytes32(proof[0x40:0x60])); // Commitments - p.w1 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x60:0x80])), - x_1: uint256(bytes32(proof[0x80:0xa0])), - y_0: uint256(bytes32(proof[0xa0:0xc0])), - y_1: uint256(bytes32(proof[0xc0:0xe0])) - }); - - p.w2 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0xe0:0x100])), - x_1: uint256(bytes32(proof[0x100:0x120])), - y_0: uint256(bytes32(proof[0x120:0x140])), - y_1: uint256(bytes32(proof[0x140:0x160])) - }); - p.w3 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x160:0x180])), - x_1: uint256(bytes32(proof[0x180:0x1a0])), - y_0: uint256(bytes32(proof[0x1a0:0x1c0])), - y_1: uint256(bytes32(proof[0x1c0:0x1e0])) - }); + p.w1 = bytesToG1ProofPoint(proof[0x60:0xe0]); + + p.w2 = bytesToG1ProofPoint(proof[0xe0:0x160]); + p.w3 = bytesToG1ProofPoint(proof[0x160:0x1e0]); // Lookup / Permutation Helper Commitments - p.lookupReadCounts = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x1e0:0x200])), - x_1: uint256(bytes32(proof[0x200:0x220])), - y_0: uint256(bytes32(proof[0x220:0x240])), - y_1: uint256(bytes32(proof[0x240:0x260])) - }); - p.lookupReadTags = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x260:0x280])), - x_1: uint256(bytes32(proof[0x280:0x2a0])), - y_0: uint256(bytes32(proof[0x2a0:0x2c0])), - y_1: uint256(bytes32(proof[0x2c0:0x2e0])) - }); - p.w4 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x2e0:0x300])), - x_1: uint256(bytes32(proof[0x300:0x320])), - y_0: uint256(bytes32(proof[0x320:0x340])), - y_1: uint256(bytes32(proof[0x340:0x360])) - }); - p.lookupInverses = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x360:0x380])), - x_1: uint256(bytes32(proof[0x380:0x3a0])), - y_0: uint256(bytes32(proof[0x3a0:0x3c0])), - y_1: uint256(bytes32(proof[0x3c0:0x3e0])) - }); - p.zPerm = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x3e0:0x400])), - x_1: uint256(bytes32(proof[0x400:0x420])), - y_0: uint256(bytes32(proof[0x420:0x440])), - y_1: uint256(bytes32(proof[0x440:0x460])) - }); - - // Boundary represents a pointer to the head of the unread part of the proof + p.lookupReadCounts = bytesToG1ProofPoint(proof[0x1e0:0x260]); + p.lookupReadTags = bytesToG1ProofPoint(proof[0x260:0x2e0]); + p.w4 = bytesToG1ProofPoint(proof[0x2e0:0x360]); + p.lookupInverses = bytesToG1ProofPoint(proof[0x360:0x3e0]); + p.zPerm = bytesToG1ProofPoint(proof[0x3e0:0x460]); + // TEMP the boundary of what has already been read uint256 boundary = 0x460; // Sumcheck univariates for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { - // The loop boundary of i, this will shift forward on each evaluation - uint256 loop_boundary = boundary + (i * 0x20 * BATCHED_RELATION_PARTIAL_LENGTH); - for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { - uint256 start = loop_boundary + (j * 0x20); - uint256 end = start + 0x20; - p.sumcheckUnivariates[i][j] = FrLib.fromBytes32(bytes32(proof[start:end])); + p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; } } - - boundary = boundary + (CONST_PROOF_SIZE_LOG_N * BATCHED_RELATION_PARTIAL_LENGTH * 0x20); // Sumcheck evaluations for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - uint256 start = boundary + (i * 0x20); - uint256 end = start + 0x20; - p.sumcheckEvaluations[i] = FrLib.fromBytes32(bytes32(proof[start:end])); + p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; } - boundary = boundary + (NUMBER_OF_ENTITIES * 0x20); - // Gemini // Read gemini fold univariates for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) { - uint256 xStart = boundary + (i * 0x80); - uint256 xEnd = xStart + 0x20; - - uint256 x1Start = xEnd; - uint256 x1End = x1Start + 0x20; - - uint256 yStart = x1End; - uint256 yEnd = yStart + 0x20; - - uint256 y1Start = yEnd; - uint256 y1End = y1Start + 0x20; - p.geminiFoldComms[i] = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[xStart:xEnd])), - x_1: uint256(bytes32(proof[x1Start:x1End])), - y_0: uint256(bytes32(proof[yStart:yEnd])), - y_1: uint256(bytes32(proof[y1Start:y1End])) - }); + p.geminiFoldComms[i] = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; } - boundary = boundary + ((CONST_PROOF_SIZE_LOG_N - 1) * 0x80); - // Read gemini a evaluations for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { - uint256 start = boundary + (i * 0x20); - uint256 end = start + 0x20; - p.geminiAEvaluations[i] = FrLib.fromBytes32(bytes32(proof[start:end])); + p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; } - boundary = boundary + (CONST_PROOF_SIZE_LOG_N * 0x20); - // Shplonk - p.shplonkQ = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[boundary:boundary + 0x20])), - x_1: uint256(bytes32(proof[boundary + 0x20:boundary + 0x40])), - y_0: uint256(bytes32(proof[boundary + 0x40:boundary + 0x60])), - y_1: uint256(bytes32(proof[boundary + 0x60:boundary + 0x80])) - }); - + p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); boundary = boundary + 0x80; - // KZG - p.kzgQuotient = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[boundary:boundary + 0x20])), - x_1: uint256(bytes32(proof[boundary + 0x20:boundary + 0x40])), - y_0: uint256(bytes32(proof[boundary + 0x40:boundary + 0x60])), - y_1: uint256(bytes32(proof[boundary + 0x60:boundary + 0x80])) - }); - - return p; + p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); } } + +// Fr utility + +function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { + require(proofSection.length == 0x20, "invalid bytes scalar"); + scalar = FrLib.fromBytes32(bytes32(proofSection)); +} + // EC Point utilities + function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) { return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)}); } +function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) { + require(proofSection.length == 0x80, "invalid bytes point"); + point = Honk.G1ProofPoint({ + x_0: uint256(bytes32(proofSection[0x00:0x20])), + x_1: uint256(bytes32(proofSection[0x20:0x40])), + y_0: uint256(bytes32(proofSection[0x40:0x60])), + y_1: uint256(bytes32(proofSection[0x60:0x80])) + }); +} + function ecMul(Honk.G1Point memory point, Fr scalar) view returns (Honk.G1Point memory) { bytes memory input = abi.encodePacked(point.x, point.y, Fr.unwrap(scalar)); (bool success, bytes memory result) = address(0x07).staticcall(input); @@ -715,25 +720,26 @@ function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point mem library RelationsLib { Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17) - function accumulateRelationEvaluations(Honk.Proof memory proof, Transcript memory tp, Fr powPartialEval) - internal - pure - returns (Fr accumulator) - { + function accumulateRelationEvaluations( + Honk.Proof memory proof, + Honk.RelationParameters memory rp, + Fr[NUMBER_OF_ALPHAS] memory alphas, + Fr powPartialEval + ) internal pure returns (Fr accumulator) { Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations = proof.sumcheckEvaluations; Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; // Accumulate all relations in Ultra Honk - each with varying number of subrelations accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePermutationRelation(purportedEvaluations, tp, evaluations, powPartialEval); - accumulateLogDerivativeLookupRelation(purportedEvaluations, tp, evaluations, powPartialEval); + accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); + accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateAuxillaryRelation(purportedEvaluations, tp, evaluations, powPartialEval); + accumulateAuxillaryRelation(purportedEvaluations, rp, evaluations, powPartialEval); accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); // batch the subrelations with the alpha challenges to obtain the full honk relation - accumulator = scaleAndBatchSubrelations(evaluations, tp.alphas); + accumulator = scaleAndBatchSubrelations(evaluations, alphas); } /** @@ -750,6 +756,7 @@ library RelationsLib { * Ultra Arithmetic Relation * */ + function accumulateArithmeticRelation( Fr[NUMBER_OF_ENTITIES] memory p, Fr[NUMBER_OF_SUBRELATIONS] memory evals, @@ -782,7 +789,7 @@ library RelationsLib { function accumulatePermutationRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Transcript memory tp, + Honk.RelationParameters memory rp, Fr[NUMBER_OF_SUBRELATIONS] memory evals, Fr domainSep ) internal pure { @@ -790,18 +797,18 @@ library RelationsLib { Fr grand_product_denominator; { - Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * tp.beta + tp.gamma; - num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * tp.beta + tp.gamma); - num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * tp.beta + tp.gamma); - num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * tp.beta + tp.gamma); + Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; + num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); + num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); + num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); grand_product_numerator = num; } { - Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * tp.beta + tp.gamma; - den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * tp.beta + tp.gamma); - den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * tp.beta + tp.gamma); - den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * tp.beta + tp.gamma); + Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; + den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); + den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); + den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); grand_product_denominator = den; } @@ -812,7 +819,7 @@ library RelationsLib { acc = acc - ( - (wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * tp.publicInputsDelta)) + (wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) * grand_product_denominator ); acc = acc * domainSep; @@ -828,7 +835,7 @@ library RelationsLib { function accumulateLogDerivativeLookupRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Transcript memory tp, + Honk.RelationParameters memory rp, Fr[NUMBER_OF_SUBRELATIONS] memory evals, Fr domainSep ) internal pure { @@ -837,18 +844,18 @@ library RelationsLib { // Calculate the write term (the table accumulation) { - write_term = wire(p, WIRE.TABLE_1) + tp.gamma + (wire(p, WIRE.TABLE_2) * tp.eta) - + (wire(p, WIRE.TABLE_3) * tp.etaTwo) + (wire(p, WIRE.TABLE_4) * tp.etaThree); + write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) + + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); } // Calculate the write term { - Fr derived_entry_1 = wire(p, WIRE.W_L) + tp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); + Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); - read_term = derived_entry_1 + (derived_entry_2 * tp.eta) + (derived_entry_3 * tp.etaTwo) - + (wire(p, WIRE.Q_O) * tp.etaThree); + read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) + + (wire(p, WIRE.Q_O) * rp.etaThree); } Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; @@ -1041,9 +1048,9 @@ library RelationsLib { function accumulateAuxillaryRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Transcript memory tp, + Honk.RelationParameters memory rp, // sooo we take the relation parameters, if needed, from tramscript Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep + Fr domainSep // i guess this is the scaling factor? ) internal pure { AuxParams memory ap; @@ -1152,9 +1159,9 @@ library RelationsLib { * * For ROM gates, qc = 0 */ - ap.memory_record_check = wire(p, WIRE.W_O) * tp.etaThree; - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * tp.etaTwo); - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * tp.eta); + ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; + ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); + ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); @@ -1211,9 +1218,12 @@ library RelationsLib { Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8 - ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * tp.etaThree; - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * tp.etaTwo); - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * tp.eta); + // TODO(htrps://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in + // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta + // deg 1 or 4 + ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; + ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); + ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); @@ -1269,6 +1279,7 @@ library RelationsLib { evals[12] = ap.auxiliary_identity; } + // Big todo for poseidon params, reduce them struct PoseidonExternalParams { Fr s1; Fr s2; @@ -1292,7 +1303,7 @@ library RelationsLib { function accumulatePoseidonExternalRelation( Fr[NUMBER_OF_ENTITIES] memory p, Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep + Fr domainSep // i guess this is the scaling factor? ) internal pure { PoseidonExternalParams memory ep; @@ -1398,7 +1409,6 @@ library RelationsLib { } } - interface IVerifier { function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); } @@ -1434,10 +1444,6 @@ abstract contract BaseHonkVerifier is IVerifier { // Generate the fiat shamir challenges for the whole protocol Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.publicInputsSize); - // Compute the public input delta - t.publicInputsDelta = - computePublicInputDelta(publicInputs, t.beta, t.gamma, vk.circuitSize, p.publicInputsOffset); - // Sumcheck bool sumcheckVerified = verifySumcheck(p, t); if (!sumcheckVerified) revert SumcheckFailed(); @@ -1448,35 +1454,6 @@ abstract contract BaseHonkVerifier is IVerifier { return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :) } - function computePublicInputDelta( - bytes32[] memory publicInputs, - Fr beta, - Fr gamma, - uint256 domainSize, - uint256 offset - ) internal view returns (Fr publicInputDelta) { - Fr numerator = Fr.wrap(1); - Fr denominator = Fr.wrap(1); - - Fr numeratorAcc = gamma + (beta * FrLib.from(domainSize + offset)); - Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); - - { - for (uint256 i = 0; i < numPublicInputs; i++) { - Fr pubInput = FrLib.fromBytes32(publicInputs[i]); - - numerator = numerator * (numeratorAcc + pubInput); - denominator = denominator * (denominatorAcc + pubInput); - - numeratorAcc = numeratorAcc + beta; - denominatorAcc = denominatorAcc - beta; - } - } - - // Fr delta = numerator / denominator; // TOOO: batch invert later? - publicInputDelta = FrLib.div(numerator, denominator); - } - uint256 constant ROUND_TARGET = 0; function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) { @@ -1497,7 +1474,8 @@ abstract contract BaseHonkVerifier is IVerifier { } // Last round - Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations(proof, tp, powPartialEvaluation); + Fr grandHonkRelationSum = + RelationsLib.accumulateRelationEvaluations(proof, tp.relationParameters, tp.alphas, powPartialEvaluation); verified = (grandHonkRelationSum == roundTarget); } diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 5c38218a041d..5440c1e4b98a 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -54,9 +54,6 @@ abstract contract BaseHonkVerifier is IVerifier { // Generate the fiat shamir challenges for the whole protocol Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, numPublicInputs); - // Compute the public input delta - t.publicInputsDelta = computePublicInputDelta(publicInputs, t.beta, t.gamma, p.publicInputsOffset); - // Sumcheck bool sumcheckVerified = verifySumcheck(p, t); if (!sumcheckVerified) revert SumcheckFailed(); @@ -67,33 +64,6 @@ abstract contract BaseHonkVerifier is IVerifier { return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :) } - function computePublicInputDelta(bytes32[] memory publicInputs, Fr beta, Fr gamma, uint256 offset) - internal - view - returns (Fr publicInputDelta) - { - Fr numerator = Fr.wrap(1); - Fr denominator = Fr.wrap(1); - - Fr numeratorAcc = gamma + (beta * FrLib.from(N + offset)); - Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); - - { - for (uint256 i = 0; i < numPublicInputs; i++) { - Fr pubInput = FrLib.fromBytes32(publicInputs[i]); - - numerator = numerator * (numeratorAcc + pubInput); - denominator = denominator * (denominatorAcc + pubInput); - - numeratorAcc = numeratorAcc + beta; - denominatorAcc = denominatorAcc - beta; - } - } - - // Fr delta = numerator / denominator; // TOOO: batch invert later? - publicInputDelta = FrLib.div(numerator, denominator); - } - uint256 constant ROUND_TARGET = 0; function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) { @@ -114,7 +84,8 @@ abstract contract BaseHonkVerifier is IVerifier { } // Last round - Fr grandHonkRelationSum = RelationsLib.accumulateRelationEvaluations(proof, tp, powPartialEvaluation); + Fr grandHonkRelationSum = + RelationsLib.accumulateRelationEvaluations(proof, tp.relationParameters, tp.alphas, powPartialEvaluation); verified = (grandHonkRelationSum == roundTarget); } diff --git a/barretenberg/sol/src/honk/HonkTypes.sol b/barretenberg/sol/src/honk/HonkTypes.sol index bedb2a28a444..42a0ea36ccfe 100644 --- a/barretenberg/sol/src/honk/HonkTypes.sol +++ b/barretenberg/sol/src/honk/HonkTypes.sol @@ -111,6 +111,17 @@ library Honk { G1Point lagrangeLast; } + struct RelationParameters { + // challenges + Fr eta; + Fr etaTwo; + Fr etaThree; + Fr beta; + Fr gamma; + // derived + Fr publicInputsDelta; + } + struct Proof { uint256 circuitSize; uint256 publicInputsSize; diff --git a/barretenberg/sol/src/honk/Relations.sol b/barretenberg/sol/src/honk/Relations.sol index 251dbe8245ae..c43b4427f9aa 100644 --- a/barretenberg/sol/src/honk/Relations.sol +++ b/barretenberg/sol/src/honk/Relations.sol @@ -17,30 +17,30 @@ import {ecMul, ecAdd, ecSub, negateInplace, convertProofPoint} from "./utils.sol // Field arithmetic libraries import {MINUS_ONE, MODULUS as P, Fr, FrLib} from "./Fr.sol"; -import {Transcript, TranscriptLib} from "./Transcript.sol"; library RelationsLib { Fr internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = Fr.wrap(17); // -(-17) - function accumulateRelationEvaluations(Honk.Proof memory proof, Transcript memory tp, Fr powPartialEval) - internal - pure - returns (Fr accumulator) - { + function accumulateRelationEvaluations( + Honk.Proof memory proof, + Honk.RelationParameters memory rp, + Fr[NUMBER_OF_ALPHAS] memory alphas, + Fr powPartialEval + ) internal pure returns (Fr accumulator) { Fr[NUMBER_OF_ENTITIES] memory purportedEvaluations = proof.sumcheckEvaluations; Fr[NUMBER_OF_SUBRELATIONS] memory evaluations; // Accumulate all relations in Ultra Honk - each with varying number of subrelations accumulateArithmeticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulatePermutationRelation(purportedEvaluations, tp, evaluations, powPartialEval); - accumulateLogDerivativeLookupRelation(purportedEvaluations, tp, evaluations, powPartialEval); + accumulatePermutationRelation(purportedEvaluations, rp, evaluations, powPartialEval); + accumulateLogDerivativeLookupRelation(purportedEvaluations, rp, evaluations, powPartialEval); accumulateDeltaRangeRelation(purportedEvaluations, evaluations, powPartialEval); accumulateEllipticRelation(purportedEvaluations, evaluations, powPartialEval); - accumulateAuxillaryRelation(purportedEvaluations, tp, evaluations, powPartialEval); + accumulateAuxillaryRelation(purportedEvaluations, rp, evaluations, powPartialEval); accumulatePoseidonExternalRelation(purportedEvaluations, evaluations, powPartialEval); accumulatePoseidonInternalRelation(purportedEvaluations, evaluations, powPartialEval); // batch the subrelations with the alpha challenges to obtain the full honk relation - accumulator = scaleAndBatchSubrelations(evaluations, tp.alphas); + accumulator = scaleAndBatchSubrelations(evaluations, alphas); } /** @@ -90,7 +90,7 @@ library RelationsLib { function accumulatePermutationRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Transcript memory tp, + Honk.RelationParameters memory rp, Fr[NUMBER_OF_SUBRELATIONS] memory evals, Fr domainSep ) internal pure { @@ -98,18 +98,18 @@ library RelationsLib { Fr grand_product_denominator; { - Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * tp.beta + tp.gamma; - num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * tp.beta + tp.gamma); - num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * tp.beta + tp.gamma); - num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * tp.beta + tp.gamma); + Fr num = wire(p, WIRE.W_L) + wire(p, WIRE.ID_1) * rp.beta + rp.gamma; + num = num * (wire(p, WIRE.W_R) + wire(p, WIRE.ID_2) * rp.beta + rp.gamma); + num = num * (wire(p, WIRE.W_O) + wire(p, WIRE.ID_3) * rp.beta + rp.gamma); + num = num * (wire(p, WIRE.W_4) + wire(p, WIRE.ID_4) * rp.beta + rp.gamma); grand_product_numerator = num; } { - Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * tp.beta + tp.gamma; - den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * tp.beta + tp.gamma); - den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * tp.beta + tp.gamma); - den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * tp.beta + tp.gamma); + Fr den = wire(p, WIRE.W_L) + wire(p, WIRE.SIGMA_1) * rp.beta + rp.gamma; + den = den * (wire(p, WIRE.W_R) + wire(p, WIRE.SIGMA_2) * rp.beta + rp.gamma); + den = den * (wire(p, WIRE.W_O) + wire(p, WIRE.SIGMA_3) * rp.beta + rp.gamma); + den = den * (wire(p, WIRE.W_4) + wire(p, WIRE.SIGMA_4) * rp.beta + rp.gamma); grand_product_denominator = den; } @@ -120,7 +120,7 @@ library RelationsLib { acc = acc - ( - (wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * tp.publicInputsDelta)) + (wire(p, WIRE.Z_PERM_SHIFT) + (wire(p, WIRE.LAGRANGE_LAST) * rp.publicInputsDelta)) * grand_product_denominator ); acc = acc * domainSep; @@ -136,7 +136,7 @@ library RelationsLib { function accumulateLogDerivativeLookupRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Transcript memory tp, + Honk.RelationParameters memory rp, Fr[NUMBER_OF_SUBRELATIONS] memory evals, Fr domainSep ) internal pure { @@ -145,18 +145,18 @@ library RelationsLib { // Calculate the write term (the table accumulation) { - write_term = wire(p, WIRE.TABLE_1) + tp.gamma + (wire(p, WIRE.TABLE_2) * tp.eta) - + (wire(p, WIRE.TABLE_3) * tp.etaTwo) + (wire(p, WIRE.TABLE_4) * tp.etaThree); + write_term = wire(p, WIRE.TABLE_1) + rp.gamma + (wire(p, WIRE.TABLE_2) * rp.eta) + + (wire(p, WIRE.TABLE_3) * rp.etaTwo) + (wire(p, WIRE.TABLE_4) * rp.etaThree); } // Calculate the write term { - Fr derived_entry_1 = wire(p, WIRE.W_L) + tp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); + Fr derived_entry_1 = wire(p, WIRE.W_L) + rp.gamma + (wire(p, WIRE.Q_R) * wire(p, WIRE.W_L_SHIFT)); Fr derived_entry_2 = wire(p, WIRE.W_R) + wire(p, WIRE.Q_M) * wire(p, WIRE.W_R_SHIFT); Fr derived_entry_3 = wire(p, WIRE.W_O) + wire(p, WIRE.Q_C) * wire(p, WIRE.W_O_SHIFT); - read_term = derived_entry_1 + (derived_entry_2 * tp.eta) + (derived_entry_3 * tp.etaTwo) - + (wire(p, WIRE.Q_O) * tp.etaThree); + read_term = derived_entry_1 + (derived_entry_2 * rp.eta) + (derived_entry_3 * rp.etaTwo) + + (wire(p, WIRE.Q_O) * rp.etaThree); } Fr read_inverse = wire(p, WIRE.LOOKUP_INVERSES) * write_term; @@ -349,7 +349,7 @@ library RelationsLib { function accumulateAuxillaryRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Transcript memory tp, // sooo we take the relation parameters, if needed, from tramscript + Honk.RelationParameters memory rp, // sooo we take the relation parameters, if needed, from tramscript Fr[NUMBER_OF_SUBRELATIONS] memory evals, Fr domainSep // i guess this is the scaling factor? ) internal pure { @@ -460,9 +460,9 @@ library RelationsLib { * * For ROM gates, qc = 0 */ - ap.memory_record_check = wire(p, WIRE.W_O) * tp.etaThree; - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * tp.etaTwo); - ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * tp.eta); + ap.memory_record_check = wire(p, WIRE.W_O) * rp.etaThree; + ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_R) * rp.etaTwo); + ap.memory_record_check = ap.memory_record_check + (wire(p, WIRE.W_L) * rp.eta); ap.memory_record_check = ap.memory_record_check + wire(p, WIRE.Q_C); ap.partial_record_check = ap.memory_record_check; // used in RAM consistency check; deg 1 or 4 ap.memory_record_check = ap.memory_record_check - wire(p, WIRE.W_4); @@ -519,12 +519,12 @@ library RelationsLib { Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8 - // TODO(https://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in + // TODO(htrps://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta // deg 1 or 4 - ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * tp.etaThree; - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * tp.etaTwo); - ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * tp.eta); + ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; + ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); + ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); ap.next_gate_access_type = wire(p, WIRE.W_4_SHIFT) - ap.next_gate_access_type; Fr value_delta = wire(p, WIRE.W_O_SHIFT) - wire(p, WIRE.W_O); diff --git a/barretenberg/sol/src/honk/Transcript.sol b/barretenberg/sol/src/honk/Transcript.sol index ca4e14497165..924ea9a112e5 100644 --- a/barretenberg/sol/src/honk/Transcript.sol +++ b/barretenberg/sol/src/honk/Transcript.sol @@ -8,36 +8,33 @@ import { CONST_PROOF_SIZE_LOG_N } from "./HonkTypes.sol"; import {Fr, FrLib} from "./Fr.sol"; +import {bytesToG1ProofPoint, bytesToFr} from "./utils.sol"; // Transcript library to generate fiat shamir challenges struct Transcript { - Fr eta; - Fr etaTwo; - Fr etaThree; - Fr beta; - Fr gamma; + // Oink + Honk.RelationParameters relationParameters; Fr[NUMBER_OF_ALPHAS] alphas; Fr[CONST_PROOF_SIZE_LOG_N] gateChallenges; + // Sumcheck Fr[CONST_PROOF_SIZE_LOG_N] sumCheckUChallenges; // Gemini Fr rho; Fr geminiR; + // Shplonk Fr shplonkNu; Fr shplonkZ; - // Derived - Fr publicInputsDelta; } library TranscriptLib { function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) internal - pure + view returns (Transcript memory t) { Fr previousChallenge; - (t.eta, t.etaTwo, t.etaThree, previousChallenge) = generateEtaChallenge(proof, publicInputs, publicInputsSize); - - (t.beta, t.gamma, previousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + (t.relationParameters, previousChallenge) = + generateRelationParameters(proof, publicInputs, publicInputsSize, previousChallenge); (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); @@ -64,6 +61,65 @@ library TranscriptLib { second = FrLib.fromBytes32(bytes32(hi)); } + function generateRelationParameters( + Honk.Proof memory proof, + bytes32[] calldata publicInputs, + uint256 publicInputsSize, + Fr previousChallenge + ) internal view returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = + generateEtaChallenge(proof, publicInputs, publicInputsSize); + + (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + + // Derive public input delta + rp.publicInputsDelta = computePublicInputDelta( + publicInputs, publicInputsSize, rp.beta, rp.gamma, proof.circuitSize, proof.publicInputsOffset + ); + } + + function computePublicInputDelta( + bytes32[] memory publicInputs, + uint256 publicInputsSize, + Fr beta, + Fr gamma, + uint256 circuitSize, + uint256 offset + ) internal view returns (Fr publicInputDelta) { + Fr numerator = Fr.wrap(1); + Fr denominator = Fr.wrap(1); + + Fr numeratorAcc = gamma + (beta * FrLib.from(circuitSize + offset)); + Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); + + { + for (uint256 i = 0; i < publicInputsSize; i++) { + Fr pubInput = FrLib.fromBytes32(publicInputs[i]); + + numerator = numerator * (numeratorAcc + pubInput); + denominator = denominator * (denominatorAcc + pubInput); + + numeratorAcc = numeratorAcc + beta; + denominatorAcc = denominatorAcc - beta; + } + } + + // Fr delta = numerator / denominator; // TOOO: batch invert later? + publicInputDelta = FrLib.div(numerator, denominator); + } + + function generateChallengeRelationParameters( + Honk.Proof memory proof, + bytes32[] calldata publicInputs, + uint256 publicInputsSize, + Fr previousChallenge + ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = + generateEtaChallenge(proof, publicInputs, publicInputsSize); + + (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); + } + function generateEtaChallenge(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) internal pure @@ -265,145 +321,57 @@ library TranscriptLib { // TODO: Preprocess all of the memory locations // TODO: Adjust proof point serde away from poseidon forced field elements // TODO: move this back to probably each instance to avoid dynamic init of arrays in the Transcript Lib - function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory) { - Honk.Proof memory p; - + function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) { // Metadata p.circuitSize = uint256(bytes32(proof[0x00:0x20])); p.publicInputsSize = uint256(bytes32(proof[0x20:0x40])); p.publicInputsOffset = uint256(bytes32(proof[0x40:0x60])); // Commitments - p.w1 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x60:0x80])), - x_1: uint256(bytes32(proof[0x80:0xa0])), - y_0: uint256(bytes32(proof[0xa0:0xc0])), - y_1: uint256(bytes32(proof[0xc0:0xe0])) - }); - - p.w2 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0xe0:0x100])), - x_1: uint256(bytes32(proof[0x100:0x120])), - y_0: uint256(bytes32(proof[0x120:0x140])), - y_1: uint256(bytes32(proof[0x140:0x160])) - }); - p.w3 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x160:0x180])), - x_1: uint256(bytes32(proof[0x180:0x1a0])), - y_0: uint256(bytes32(proof[0x1a0:0x1c0])), - y_1: uint256(bytes32(proof[0x1c0:0x1e0])) - }); + p.w1 = bytesToG1ProofPoint(proof[0x60:0xe0]); - // Lookup / Permutation Helper Commitments - p.lookupReadCounts = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x1e0:0x200])), - x_1: uint256(bytes32(proof[0x200:0x220])), - y_0: uint256(bytes32(proof[0x220:0x240])), - y_1: uint256(bytes32(proof[0x240:0x260])) - }); - p.lookupReadTags = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x260:0x280])), - x_1: uint256(bytes32(proof[0x280:0x2a0])), - y_0: uint256(bytes32(proof[0x2a0:0x2c0])), - y_1: uint256(bytes32(proof[0x2c0:0x2e0])) - }); - p.w4 = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x2e0:0x300])), - x_1: uint256(bytes32(proof[0x300:0x320])), - y_0: uint256(bytes32(proof[0x320:0x340])), - y_1: uint256(bytes32(proof[0x340:0x360])) - }); - p.lookupInverses = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x360:0x380])), - x_1: uint256(bytes32(proof[0x380:0x3a0])), - y_0: uint256(bytes32(proof[0x3a0:0x3c0])), - y_1: uint256(bytes32(proof[0x3c0:0x3e0])) - }); - p.zPerm = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[0x3e0:0x400])), - x_1: uint256(bytes32(proof[0x400:0x420])), - y_0: uint256(bytes32(proof[0x420:0x440])), - y_1: uint256(bytes32(proof[0x440:0x460])) - }); + p.w2 = bytesToG1ProofPoint(proof[0xe0:0x160]); + p.w3 = bytesToG1ProofPoint(proof[0x160:0x1e0]); + // Lookup / Permutation Helper Commitments + p.lookupReadCounts = bytesToG1ProofPoint(proof[0x1e0:0x260]); + p.lookupReadTags = bytesToG1ProofPoint(proof[0x260:0x2e0]); + p.w4 = bytesToG1ProofPoint(proof[0x2e0:0x360]); + p.lookupInverses = bytesToG1ProofPoint(proof[0x360:0x3e0]); + p.zPerm = bytesToG1ProofPoint(proof[0x3e0:0x460]); // TEMP the boundary of what has already been read uint256 boundary = 0x460; // Sumcheck univariates - // TODO: in this case we know what log_n is - so we hard code it, we would want this to be included in - // a cpp template for different circuit sizes for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { - // The loop boundary of i, this will shift forward on each evaluation - uint256 loop_boundary = boundary + (i * 0x20 * BATCHED_RELATION_PARTIAL_LENGTH); - for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { - uint256 start = loop_boundary + (j * 0x20); - uint256 end = start + 0x20; - p.sumcheckUnivariates[i][j] = FrLib.fromBytes32(bytes32(proof[start:end])); + p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; } } - - boundary = boundary + (CONST_PROOF_SIZE_LOG_N * BATCHED_RELATION_PARTIAL_LENGTH * 0x20); // Sumcheck evaluations for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - uint256 start = boundary + (i * 0x20); - uint256 end = start + 0x20; - p.sumcheckEvaluations[i] = FrLib.fromBytes32(bytes32(proof[start:end])); + p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; } - boundary = boundary + (NUMBER_OF_ENTITIES * 0x20); - // Gemini // Read gemini fold univariates for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; i++) { - uint256 xStart = boundary + (i * 0x80); - uint256 xEnd = xStart + 0x20; - - uint256 x1Start = xEnd; - uint256 x1End = x1Start + 0x20; - - uint256 yStart = x1End; - uint256 yEnd = yStart + 0x20; - - uint256 y1Start = yEnd; - uint256 y1End = y1Start + 0x20; - p.geminiFoldComms[i] = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[xStart:xEnd])), - x_1: uint256(bytes32(proof[x1Start:x1End])), - y_0: uint256(bytes32(proof[yStart:yEnd])), - y_1: uint256(bytes32(proof[y1Start:y1End])) - }); + p.geminiFoldComms[i] = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; } - boundary = boundary + ((CONST_PROOF_SIZE_LOG_N - 1) * 0x80); - // Read gemini a evaluations for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { - uint256 start = boundary + (i * 0x20); - uint256 end = start + 0x20; - p.geminiAEvaluations[i] = FrLib.fromBytes32(bytes32(proof[start:end])); + p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; } - boundary = boundary + (CONST_PROOF_SIZE_LOG_N * 0x20); - // Shplonk - p.shplonkQ = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[boundary:boundary + 0x20])), - x_1: uint256(bytes32(proof[boundary + 0x20:boundary + 0x40])), - y_0: uint256(bytes32(proof[boundary + 0x40:boundary + 0x60])), - y_1: uint256(bytes32(proof[boundary + 0x60:boundary + 0x80])) - }); - + p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); boundary = boundary + 0x80; - // KZG - p.kzgQuotient = Honk.G1ProofPoint({ - x_0: uint256(bytes32(proof[boundary:boundary + 0x20])), - x_1: uint256(bytes32(proof[boundary + 0x20:boundary + 0x40])), - y_0: uint256(bytes32(proof[boundary + 0x40:boundary + 0x60])), - y_1: uint256(bytes32(proof[boundary + 0x60:boundary + 0x80])) - }); - - return p; + p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); } } diff --git a/barretenberg/sol/src/honk/utils.sol b/barretenberg/sol/src/honk/utils.sol index 55c0e73806e9..c586800adaf8 100644 --- a/barretenberg/sol/src/honk/utils.sol +++ b/barretenberg/sol/src/honk/utils.sol @@ -70,12 +70,29 @@ function logFr(string memory name, uint256 i, Fr value) pure { console2.log(name, i, as_hex); } +// Fr utility + +function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { + require(proofSection.length == 0x20, "invalid bytes scalar"); + scalar = FrLib.fromBytes32(bytes32(proofSection)); +} + // EC Point utilities function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) { return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)}); } +function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) { + require(proofSection.length == 0x80, "invalid bytes point"); + point = Honk.G1ProofPoint({ + x_0: uint256(bytes32(proofSection[0x00:0x20])), + x_1: uint256(bytes32(proofSection[0x20:0x40])), + y_0: uint256(bytes32(proofSection[0x40:0x60])), + y_1: uint256(bytes32(proofSection[0x60:0x80])) + }); +} + function ecMul(Honk.G1Point memory point, Fr scalar) view returns (Honk.G1Point memory) { bytes memory input = abi.encodePacked(point.x, point.y, Fr.unwrap(scalar)); (bool success, bytes memory result) = address(0x07).staticcall(input); From 9349c84612eb6dda54a228e8d7bc04bbe5e0eb1f Mon Sep 17 00:00:00 2001 From: maramihali Date: Fri, 10 Jan 2025 16:28:32 +0000 Subject: [PATCH 2/4] cleanup --- .../dsl/acir_proofs/honk_contract.hpp | 25 +++++++------------ barretenberg/sol/src/honk/Relations.sol | 2 +- barretenberg/sol/src/honk/Transcript.sol | 4 +-- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 070cf069eaf7..e6c161784a9a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -311,7 +311,7 @@ struct Transcript { library TranscriptLib { function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) internal - view + pure returns (Transcript memory t) { Fr previousChallenge; @@ -348,7 +348,7 @@ library TranscriptLib { bytes32[] calldata publicInputs, uint256 publicInputsSize, Fr previousChallenge - ) internal view returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = generateEtaChallenge(proof, publicInputs, publicInputsSize); @@ -367,7 +367,7 @@ library TranscriptLib { Fr gamma, uint256 circuitSize, uint256 offset - ) internal view returns (Fr publicInputDelta) { + ) internal pure returns (Fr publicInputDelta) { Fr numerator = Fr.wrap(1); Fr denominator = Fr.wrap(1); @@ -515,7 +515,6 @@ library TranscriptLib { Fr[BATCHED_RELATION_PARTIAL_LENGTH + 1] memory univariateChal; univariateChal[0] = prevChallenge; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1098): memcpy for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { univariateChal[j + 1] = proof.sumcheckUnivariates[i][j]; } @@ -534,7 +533,6 @@ library TranscriptLib { Fr[NUMBER_OF_ENTITIES + 1] memory rhoChallengeElements; rhoChallengeElements[0] = prevChallenge; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1098): memcpy for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { rhoChallengeElements[i + 1] = proof.sumcheckEvaluations[i]; } @@ -599,11 +597,9 @@ library TranscriptLib { (shplonkZ, unused) = splitChallenge(nextPreviousChallenge); } - // TODO: mod q proof points - // TODO: Preprocess all of the memory locations - // TODO: Adjust proof point serde away from poseidon forced field elements - // TODO: move this back to probably each instance to avoid dynamic init of arrays in the Transcript Lib - function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) { + function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory) { + Honk.Proof memory p; + // Metadata p.circuitSize = uint256(bytes32(proof[0x00:0x20])); p.publicInputsSize = uint256(bytes32(proof[0x20:0x40])); @@ -621,7 +617,6 @@ library TranscriptLib { p.w4 = bytesToG1ProofPoint(proof[0x2e0:0x360]); p.lookupInverses = bytesToG1ProofPoint(proof[0x360:0x3e0]); p.zPerm = bytesToG1ProofPoint(proof[0x3e0:0x460]); - // TEMP the boundary of what has already been read uint256 boundary = 0x460; // Sumcheck univariates @@ -667,7 +662,6 @@ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { } // EC Point utilities - function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1Point memory) { return Honk.G1Point({x: input.x_0 | (input.x_1 << 136), y: input.y_0 | (input.y_1 << 136)}); } @@ -756,7 +750,6 @@ library RelationsLib { * Ultra Arithmetic Relation * */ - function accumulateArithmeticRelation( Fr[NUMBER_OF_ENTITIES] memory p, Fr[NUMBER_OF_SUBRELATIONS] memory evals, @@ -1048,9 +1041,9 @@ library RelationsLib { function accumulateAuxillaryRelation( Fr[NUMBER_OF_ENTITIES] memory p, - Honk.RelationParameters memory rp, // sooo we take the relation parameters, if needed, from tramscript + Honk.RelationParameters memory rp, Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep // i guess this is the scaling factor? + Fr domainSep ) internal pure { AuxParams memory ap; @@ -1303,7 +1296,7 @@ library RelationsLib { function accumulatePoseidonExternalRelation( Fr[NUMBER_OF_ENTITIES] memory p, Fr[NUMBER_OF_SUBRELATIONS] memory evals, - Fr domainSep // i guess this is the scaling factor? + Fr domainSep ) internal pure { PoseidonExternalParams memory ep; diff --git a/barretenberg/sol/src/honk/Relations.sol b/barretenberg/sol/src/honk/Relations.sol index c43b4427f9aa..23eab4ba5e24 100644 --- a/barretenberg/sol/src/honk/Relations.sol +++ b/barretenberg/sol/src/honk/Relations.sol @@ -519,7 +519,7 @@ library RelationsLib { Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8 - // TODO(htrps://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in + // TODO(https://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta // deg 1 or 4 ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; diff --git a/barretenberg/sol/src/honk/Transcript.sol b/barretenberg/sol/src/honk/Transcript.sol index 924ea9a112e5..5eb5d8ef1149 100644 --- a/barretenberg/sol/src/honk/Transcript.sol +++ b/barretenberg/sol/src/honk/Transcript.sol @@ -29,7 +29,7 @@ struct Transcript { library TranscriptLib { function generateTranscript(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) internal - view + pure returns (Transcript memory t) { Fr previousChallenge; @@ -66,7 +66,7 @@ library TranscriptLib { bytes32[] calldata publicInputs, uint256 publicInputsSize, Fr previousChallenge - ) internal view returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { + ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = generateEtaChallenge(proof, publicInputs, publicInputsSize); From 2b17f69528b4681cbd43d1823be2a545d3b14b57 Mon Sep 17 00:00:00 2001 From: maramihali Date: Fri, 10 Jan 2025 17:41:20 +0000 Subject: [PATCH 3/4] cleanup --- barretenberg/acir_tests/sol-test/src/index.js | 22 ++++- .../dsl/acir_proofs/honk_contract.hpp | 92 ++++++++----------- .../sol/src/honk/BaseHonkVerifier.sol | 32 +++++++ barretenberg/sol/src/honk/Transcript.sol | 51 +--------- 4 files changed, 90 insertions(+), 107 deletions(-) diff --git a/barretenberg/acir_tests/sol-test/src/index.js b/barretenberg/acir_tests/sol-test/src/index.js index b1c28cd6c183..473bb830479f 100644 --- a/barretenberg/acir_tests/sol-test/src/index.js +++ b/barretenberg/acir_tests/sol-test/src/index.js @@ -3,11 +3,16 @@ const { readFileSync, promises: fsPromises } = fs; import { spawn } from "child_process"; import { ethers } from "ethers"; import solc from "solc"; +import { error } from "console"; // Size excluding number of public inputs const NUMBER_OF_FIELDS_IN_PLONK_PROOF = 93; const NUMBER_OF_FIELDS_IN_HONK_PROOF = 443; +const WRONG_PUBLIC_INPUTS_LENGTH = "0xfa066593"; +const SUMCHECK_FAILED = "0x9fc3a218"; +const SHPLEMINI_FAILED = "0xa5d82e8a"; + // We use the solcjs compiler version in this test, although it is slower than foundry, to run the test end to end // it simplifies of parallelising the test suite @@ -97,7 +102,6 @@ var output = JSON.parse(solc.compile(JSON.stringify(compilationInput))); if (output.errors.some((e) => e.severity == "error")) { throw new Error(JSON.stringify(output.errors, null, 2)); } - const contract = output.contracts["Test.sol"]["Test"]; const bytecode = contract.evm.bytecode.object; const abi = contract.abi; @@ -237,8 +241,20 @@ try { const result = await contract.test(proofStr, publicInputs); if (!result) throw new Error("Test failed"); } catch (e) { - console.error(testName, " failed"); - console.log(e); + console.error(testName, "failed"); + if (testingHonk) { + var errorType = e.data; + switch (errorType) { + case WRONG_PUBLIC_INPUTS_LENGTH: + throw new Error("Number of inputs in the proof is wrong"); + case SUMCHECK_FAILED: + throw new Error("Sumcheck round failed"); + case SHPLEMINI_FAILED: + throw new Error("PCS round failed"); + default: + throw e; + } + } throw e; } finally { // Kill anvil at the end of running diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index e6c161784a9a..45b72b21ba6a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -316,7 +316,8 @@ library TranscriptLib { { Fr previousChallenge; (t.relationParameters, previousChallenge) = - generateRelationParameters(proof, publicInputs, publicInputsSize, previousChallenge); + generateRelationParametersChallenges(proof, publicInputs, publicInputsSize, previousChallenge); + (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); @@ -343,7 +344,7 @@ library TranscriptLib { second = FrLib.fromBytes32(bytes32(hi)); } - function generateRelationParameters( + function generateRelationParametersChallenges( Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize, @@ -354,52 +355,6 @@ library TranscriptLib { (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); - // Derive public input delta - rp.publicInputsDelta = computePublicInputDelta( - publicInputs, publicInputsSize, rp.beta, rp.gamma, proof.circuitSize, proof.publicInputsOffset - ); - } - - function computePublicInputDelta( - bytes32[] memory publicInputs, - uint256 publicInputsSize, - Fr beta, - Fr gamma, - uint256 circuitSize, - uint256 offset - ) internal pure returns (Fr publicInputDelta) { - Fr numerator = Fr.wrap(1); - Fr denominator = Fr.wrap(1); - - Fr numeratorAcc = gamma + (beta * FrLib.from(circuitSize + offset)); - Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); - - { - for (uint256 i = 0; i < publicInputsSize; i++) { - Fr pubInput = FrLib.fromBytes32(publicInputs[i]); - - numerator = numerator * (numeratorAcc + pubInput); - denominator = denominator * (denominatorAcc + pubInput); - - numeratorAcc = numeratorAcc + beta; - denominatorAcc = denominatorAcc - beta; - } - } - - // Fr delta = numerator / denominator; // TOOO: batch invert later? - publicInputDelta = FrLib.div(numerator, denominator); - } - - function generateChallengeRelationParameters( - Honk.Proof memory proof, - bytes32[] calldata publicInputs, - uint256 publicInputsSize, - Fr previousChallenge - ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { - (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = - generateEtaChallenge(proof, publicInputs, publicInputsSize); - - (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); } function generateEtaChallenge(Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize) @@ -597,9 +552,7 @@ library TranscriptLib { (shplonkZ, unused) = splitChallenge(nextPreviousChallenge); } - function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory) { - Honk.Proof memory p; - + function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) { // Metadata p.circuitSize = uint256(bytes32(proof[0x00:0x20])); p.publicInputsSize = uint256(bytes32(proof[0x20:0x40])); @@ -1211,9 +1164,6 @@ library RelationsLib { Fr access_type = (wire(p, WIRE.W_4) - ap.partial_record_check); // will be 0 or 1 for honest Prover; deg 1 or 4 ap.access_check = access_type * access_type - access_type; // check value is 0 or 1; deg 2 or 8 - // TODO(htrps://github.com/AztecProtocol/barretenberg/issues/757): If we sorted in - // reverse order we could re-use `ap.partial_record_check` 1 - ((w3' * eta + w2') * eta + w1') * eta - // deg 1 or 4 ap.next_gate_access_type = wire(p, WIRE.W_O_SHIFT) * rp.etaThree; ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_R_SHIFT) * rp.etaTwo); ap.next_gate_access_type = ap.next_gate_access_type + (wire(p, WIRE.W_L_SHIFT) * rp.eta); @@ -1272,7 +1222,6 @@ library RelationsLib { evals[12] = ap.auxiliary_identity; } - // Big todo for poseidon params, reduce them struct PoseidonExternalParams { Fr s1; Fr s2; @@ -1402,6 +1351,7 @@ library RelationsLib { } } + interface IVerifier { function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); } @@ -1437,6 +1387,11 @@ abstract contract BaseHonkVerifier is IVerifier { // Generate the fiat shamir challenges for the whole protocol Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, vk.publicInputsSize); + // Derive public input delta + t.relationParameters.publicInputsDelta = computePublicInputDelta( + publicInputs, t.relationParameters.beta, t.relationParameters.gamma, p.publicInputsOffset + ); + // Sumcheck bool sumcheckVerified = verifySumcheck(p, t); if (!sumcheckVerified) revert SumcheckFailed(); @@ -1447,6 +1402,33 @@ abstract contract BaseHonkVerifier is IVerifier { return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :) } + function computePublicInputDelta(bytes32[] memory publicInputs, Fr beta, Fr gamma, uint256 offset) + internal + view + returns (Fr publicInputDelta) + { + Fr numerator = Fr.wrap(1); + Fr denominator = Fr.wrap(1); + + Fr numeratorAcc = gamma + (beta * FrLib.from(N + offset)); + Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); + + { + for (uint256 i = 0; i < numPublicInputs; i++) { + Fr pubInput = FrLib.fromBytes32(publicInputs[i]); + + numerator = numerator * (numeratorAcc + pubInput); + denominator = denominator * (denominatorAcc + pubInput); + + numeratorAcc = numeratorAcc + beta; + denominatorAcc = denominatorAcc - beta; + } + } + + // Fr delta = numerator / denominator; // TOOO: batch invert later? + publicInputDelta = FrLib.div(numerator, denominator); + } + uint256 constant ROUND_TARGET = 0; function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) { diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index 5440c1e4b98a..8d63c71aa8de 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -54,6 +54,11 @@ abstract contract BaseHonkVerifier is IVerifier { // Generate the fiat shamir challenges for the whole protocol Transcript memory t = TranscriptLib.generateTranscript(p, publicInputs, numPublicInputs); + // Derive public input delta + t.relationParameters.publicInputsDelta = computePublicInputDelta( + publicInputs, t.relationParameters.beta, t.relationParameters.gamma, p.publicInputsOffset + ); + // Sumcheck bool sumcheckVerified = verifySumcheck(p, t); if (!sumcheckVerified) revert SumcheckFailed(); @@ -64,6 +69,33 @@ abstract contract BaseHonkVerifier is IVerifier { return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :) } + function computePublicInputDelta(bytes32[] memory publicInputs, Fr beta, Fr gamma, uint256 offset) + internal + view + returns (Fr publicInputDelta) + { + Fr numerator = Fr.wrap(1); + Fr denominator = Fr.wrap(1); + + Fr numeratorAcc = gamma + (beta * FrLib.from(N + offset)); + Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); + + { + for (uint256 i = 0; i < numPublicInputs; i++) { + Fr pubInput = FrLib.fromBytes32(publicInputs[i]); + + numerator = numerator * (numeratorAcc + pubInput); + denominator = denominator * (denominatorAcc + pubInput); + + numeratorAcc = numeratorAcc + beta; + denominatorAcc = denominatorAcc - beta; + } + } + + // Fr delta = numerator / denominator; // TOOO: batch invert later? + publicInputDelta = FrLib.div(numerator, denominator); + } + uint256 constant ROUND_TARGET = 0; function verifySumcheck(Honk.Proof memory proof, Transcript memory tp) internal view returns (bool verified) { diff --git a/barretenberg/sol/src/honk/Transcript.sol b/barretenberg/sol/src/honk/Transcript.sol index 5eb5d8ef1149..7cd47a60bd9b 100644 --- a/barretenberg/sol/src/honk/Transcript.sol +++ b/barretenberg/sol/src/honk/Transcript.sol @@ -34,7 +34,7 @@ library TranscriptLib { { Fr previousChallenge; (t.relationParameters, previousChallenge) = - generateRelationParameters(proof, publicInputs, publicInputsSize, previousChallenge); + generateRelationParametersChallenges(proof, publicInputs, publicInputsSize, previousChallenge); (t.alphas, previousChallenge) = generateAlphaChallenges(previousChallenge, proof); @@ -61,54 +61,7 @@ library TranscriptLib { second = FrLib.fromBytes32(bytes32(hi)); } - function generateRelationParameters( - Honk.Proof memory proof, - bytes32[] calldata publicInputs, - uint256 publicInputsSize, - Fr previousChallenge - ) internal pure returns (Honk.RelationParameters memory rp, Fr nextPreviousChallenge) { - (rp.eta, rp.etaTwo, rp.etaThree, previousChallenge) = - generateEtaChallenge(proof, publicInputs, publicInputsSize); - - (rp.beta, rp.gamma, nextPreviousChallenge) = generateBetaAndGammaChallenges(previousChallenge, proof); - - // Derive public input delta - rp.publicInputsDelta = computePublicInputDelta( - publicInputs, publicInputsSize, rp.beta, rp.gamma, proof.circuitSize, proof.publicInputsOffset - ); - } - - function computePublicInputDelta( - bytes32[] memory publicInputs, - uint256 publicInputsSize, - Fr beta, - Fr gamma, - uint256 circuitSize, - uint256 offset - ) internal view returns (Fr publicInputDelta) { - Fr numerator = Fr.wrap(1); - Fr denominator = Fr.wrap(1); - - Fr numeratorAcc = gamma + (beta * FrLib.from(circuitSize + offset)); - Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); - - { - for (uint256 i = 0; i < publicInputsSize; i++) { - Fr pubInput = FrLib.fromBytes32(publicInputs[i]); - - numerator = numerator * (numeratorAcc + pubInput); - denominator = denominator * (denominatorAcc + pubInput); - - numeratorAcc = numeratorAcc + beta; - denominatorAcc = denominatorAcc - beta; - } - } - - // Fr delta = numerator / denominator; // TOOO: batch invert later? - publicInputDelta = FrLib.div(numerator, denominator); - } - - function generateChallengeRelationParameters( + function generateRelationParametersChallenges( Honk.Proof memory proof, bytes32[] calldata publicInputs, uint256 publicInputsSize, From 340a4443b036bc5cf71191a9782682b1d21d1f7c Mon Sep 17 00:00:00 2001 From: maramihali Date: Fri, 10 Jan 2025 17:45:36 +0000 Subject: [PATCH 4/4] remove unused import and make some errors more verbose --- barretenberg/acir_tests/sol-test/src/index.js | 1 - barretenberg/sol/src/honk/utils.sol | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/barretenberg/acir_tests/sol-test/src/index.js b/barretenberg/acir_tests/sol-test/src/index.js index 473bb830479f..e8ceb1dc260e 100644 --- a/barretenberg/acir_tests/sol-test/src/index.js +++ b/barretenberg/acir_tests/sol-test/src/index.js @@ -3,7 +3,6 @@ const { readFileSync, promises: fsPromises } = fs; import { spawn } from "child_process"; import { ethers } from "ethers"; import solc from "solc"; -import { error } from "console"; // Size excluding number of public inputs const NUMBER_OF_FIELDS_IN_PLONK_PROOF = 93; diff --git a/barretenberg/sol/src/honk/utils.sol b/barretenberg/sol/src/honk/utils.sol index c586800adaf8..33710be7e15e 100644 --- a/barretenberg/sol/src/honk/utils.sol +++ b/barretenberg/sol/src/honk/utils.sol @@ -73,7 +73,7 @@ function logFr(string memory name, uint256 i, Fr value) pure { // Fr utility function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { - require(proofSection.length == 0x20, "invalid bytes scalar"); + require(proofSection.length == 0x20, "invalid number of bytes to construct Fr scalar"); scalar = FrLib.fromBytes32(bytes32(proofSection)); } @@ -84,7 +84,7 @@ function convertProofPoint(Honk.G1ProofPoint memory input) pure returns (Honk.G1 } function bytesToG1ProofPoint(bytes calldata proofSection) pure returns (Honk.G1ProofPoint memory point) { - require(proofSection.length == 0x80, "invalid bytes point"); + require(proofSection.length == 0x80, "invalid number of bytes to construct a G1 point"); point = Honk.G1ProofPoint({ x_0: uint256(bytes32(proofSection[0x00:0x20])), x_1: uint256(bytes32(proofSection[0x20:0x40])),