20 transcript->load_proof(proof);
25 const FF binding_hash =
std::get<0>(Transcript::Codec::split_challenge(hash));
31 std::vector<FF> calculated_hashes;
32 for (
size_t idx = 0; idx < MAX_MERGE_SIZE; ++idx) {
33 for (
size_t col = 0; col < NUM_WIRES; ++col) {
34 subtable_cols[idx][col] = transcript->template receive_from_prover<Commitment>(
37 calculated_hashes.push_back(transcript->template get_challenge<FF>(
"HASH_" +
std::to_string(idx)));
43 std::array<Commitment, NUM_WIRES> zk_columns;
44 for (
size_t col = 0; col < NUM_WIRES; ++col) {
45 zk_columns[col] = transcript->template receive_from_prover<Commitment>(
"ZK_COLUMN_" +
std::to_string(col));
51 std::vector<Commitment> flattened_cols;
52 flattened_cols.reserve(NUM_EVALS_FROM_COLUMNS);
53 for (
size_t col = 0; col < NUM_WIRES; ++col) {
54 flattened_cols.push_back(
std::move(zk_columns[col]));
56 for (
auto& subtable_col : subtable_cols) {
57 for (
size_t col = 0; col < NUM_WIRES; col++) {
58 flattened_cols.push_back(
std::move(subtable_col[col]));
65 const FF N = transcript->template receive_from_prover<FF>(
"NUM_SUBTABLES");
70 FF running_product =
FF(1);
71 for (
size_t idx = 0; idx < MAX_MERGE_SIZE; idx++) {
72 running_product *= (N -
FF(idx + 1));
75 bool is_valid_num_subtables =
true;
76 if constexpr (IsRecursive) {
77 is_valid_num_subtables = running_product.get_value().is_zero();
78 running_product.assert_equal(
FF(0));
80 is_valid_num_subtables = running_product.is_zero();
83 std::vector<FF> shift_sizes;
84 shift_sizes.reserve(NUM_COLUMN_TABLES);
87 std::vector<FF> indicator_array = compute_indicator_array(N);
89 for (
size_t i = 0; i < MAX_MERGE_SIZE; ++i) {
91 shift_sizes.push_back(transcript->template receive_from_prover<FF>(
"SHIFT_SIZE_" +
std::to_string(i)));
92 shift_sizes[idx] = shift_sizes[idx] * indicator_array[i];
99 for (
size_t col = 0; col < NUM_WIRES; ++col) {
100 merged_commitments[col] =
101 transcript->template receive_from_prover<Commitment>(
"MERGED_COLUMN_" +
std::to_string(col));
107 std::vector<FF> degree_check_challenges;
108 degree_check_challenges.reserve(NUM_EVALS_FROM_COLUMNS);
109 const FF degree_check_challenge = transcript->template get_challenge<FF>(
"DEGREE_CHECK_CHALLENGE");
110 degree_check_challenges = {
FF(1), degree_check_challenge };
111 for (
size_t idx = 2; idx < NUM_EVALS_FROM_COLUMNS; idx++) {
112 degree_check_challenges.push_back(degree_check_challenges.back() * degree_check_challenge);
118 Commitment degree_check_commitment = transcript->template receive_from_prover<Commitment>(
"DEGREE_CHECK_POLY");
123 const FF kappa = transcript->template get_challenge<FF>(
"KAPPA");
124 const FF kappa_inv = kappa.invert();
126 std::vector<FF> powers_of_kappa;
127 powers_of_kappa.reserve(shift_sizes.size());
128 for (
const FF& shift_size : shift_sizes) {
129 if constexpr (IsRecursive) {
132 powers_of_kappa.push_back(kappa.template pow<CONST_OP_QUEUE_LOG_SIZE + 1>(shift_size));
135 static_cast<uint32_t
>(shift_size), 1UL << (CONST_OP_QUEUE_LOG_SIZE + 1),
"Shift size is too large");
136 powers_of_kappa.push_back(kappa.pow(shift_size));
140 std::vector<FF> powers_of_kappa_inv;
141 powers_of_kappa_inv.reserve(powers_of_kappa.size());
142 if constexpr (IsRecursive) {
143 for (
const FF& kappa_pow : powers_of_kappa) {
144 powers_of_kappa_inv.push_back(kappa_pow.invert());
147 powers_of_kappa_inv = powers_of_kappa;
155 std::vector<FF> evals;
156 evals.reserve(NUM_EVALS);
157 for (
size_t i = 0; i < NUM_EVALS_FROM_COLUMNS; ++i) {
158 const FF received_eval = transcript->template receive_from_prover<FF>(
"C_EVAL_" +
std::to_string(i));
159 evals.push_back(received_eval);
163 for (
size_t col = 0; col < NUM_WIRES; ++col) {
164 evals.push_back(transcript->template receive_from_prover<FF>(
"MERGED_EVAL_" +
std::to_string(col)));
168 evals.push_back(transcript->template receive_from_prover<FF>(
"DEGREE_CHECK_EVAL"));
175 if constexpr (IsRecursive) {
178 for (
FF& kappa_pow : powers_of_kappa) {
179 origin_tags.push_back(kappa_pow.get_origin_tag());
180 kappa_pow.set_origin_tag(evals[0].get_origin_tag());
182 for (
FF& kappa_pow : powers_of_kappa_inv) {
183 kappa_pow.set_origin_tag(evals[0].get_origin_tag());
187 const bool concatenation_verified = check_concatenation_identity(evals, powers_of_kappa);
188 const bool degree_check_verified =
189 check_degree_identity(evals, powers_of_kappa_inv, kappa, degree_check_challenges);
190 const bool hash_verified = check_hash_consistency(binding_hash, calculated_hashes, indicator_array);
193 if constexpr (IsRecursive) {
194 for (
auto [kappa_pow, origin_tag] :
zip_view(powers_of_kappa, origin_tags)) {
195 kappa_pow.set_origin_tag(origin_tag);
197 for (
auto [kappa_pow, origin_tag] :
zip_view(powers_of_kappa_inv, origin_tags)) {
198 kappa_pow.set_origin_tag(origin_tag);
206 opening_claims.reserve(NUM_OPENING_CLAIMS);
207 for (
size_t idx = 0; idx < NUM_EVALS_FROM_COLUMNS; ++idx) {
208 opening_claims.push_back(
OpeningClaim<Curve>{ { kappa, evals[idx] }, flattened_cols[idx] });
210 for (
size_t idx = 0; idx < NUM_WIRES; ++idx) {
211 opening_claims.push_back(
212 OpeningClaim<Curve>{ { kappa, evals[NUM_EVALS_FROM_COLUMNS + idx] }, merged_commitments[idx] });
214 opening_claims.push_back(
OpeningClaim<Curve>{ { kappa_inv, evals.back() }, degree_check_commitment });
216 ShplonkVerifier shplonk_verifier = ShplonkVerifier::reduce_verification_no_finalize(opening_claims, transcript);
219 if constexpr (IsRecursive) {
220 g1_identity = Commitment::one(kappa.get_context());
222 g1_identity = Commitment::one();
229 PairingPoints pairing_points = PCS::reduce_verify_batch_opening_claim(
std::move(batch_claim), transcript);
231 vinfo(
"BatchMergeVerifier: concatenation check passed: ", concatenation_verified ?
"true" :
"false");
232 vinfo(
"BatchMergeVerifier: degree check passed: ", degree_check_verified ?
"true" :
"false");
233 vinfo(
"BatchMergeVerifier: hash check passed: ", hash_verified ?
"true" :
"false");
234 vinfo(
"BatchMergeVerifier: is N in [1, MAX_MERGE_SIZE]: ", is_valid_num_subtables ?
"true" :
"false");
236 return { pairing_points,
238 degree_check_verified && concatenation_verified && hash_verified && is_valid_num_subtables };