barretenberg
Loading...
Searching...
No Matches
ipa.hpp
1#pragma once
2#include "barretenberg/commitment_schemes/claim.hpp"
3#include "barretenberg/commitment_schemes/verification_key.hpp"
4#include "barretenberg/common/assert.hpp"
5#include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp"
6#include "barretenberg/transcript/transcript.hpp"
7#include <cstddef>
8#include <numeric>
9#include <string>
10#include <vector>
11
18template <typename Curve> class IPA {
19 using Fr = typename Curve::ScalarField;
20 using GroupElement = typename Curve::Element;
21 using Commitment = typename Curve::AffineElement;
25
26 public:
36 static void compute_opening_proof(const std::shared_ptr<CK>& ck,
37 const OpeningPair<Curve>& opening_pair,
39 const std::shared_ptr<BaseTranscript>& transcript)
40 {
41 ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero");
42 auto poly_degree = static_cast<size_t>(polynomial.size());
43 transcript->send_to_verifier("IPA:poly_degree", static_cast<uint64_t>(poly_degree));
44 const Fr generator_challenge = transcript->get_challenge("IPA:generator_challenge");
45 auto aux_generator = Commitment::one() * generator_challenge;
46
47 // Checks poly_degree is greater than zero and a power of two
48 // In the future, we might want to consider if non-powers of two are needed
49 ASSERT((poly_degree > 0) && (!(poly_degree & (poly_degree - 1))) &&
50 "The poly_degree should be positive and a power of two");
51
52 auto a_vec = polynomial;
53 auto srs_elements = ck->srs->get_monomial_points();
54 std::vector<Commitment> G_vec_local(poly_degree);
55 // The SRS stored in the commitment key is the result after applying the pippenger point table so the
56 // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism
57 // G_vec_local should use only the original SRS thus we extract only the even indices.
58 for (size_t i = 0; i < poly_degree * 2; i += 2) {
59 G_vec_local[i >> 1] = srs_elements[i];
60 }
61 std::vector<Fr> b_vec(poly_degree);
62 Fr b_power = 1;
63 for (size_t i = 0; i < poly_degree; i++) {
64 b_vec[i] = b_power;
65 b_power *= opening_pair.challenge;
66 }
67 // Iterate for log(poly_degree) rounds to compute the round commitments.
68 auto log_poly_degree = static_cast<size_t>(numeric::get_msb(poly_degree));
69 std::vector<GroupElement> L_elements(log_poly_degree);
70 std::vector<GroupElement> R_elements(log_poly_degree);
71 std::size_t round_size = poly_degree;
72
73 // TODO(#479): restructure IPA so it can be integrated with the pthread alternative to work queue (or even the
74 // work queue itself). Investigate whether parallelising parts of each rounds of IPA rounds brings significant
75 // improvements and see if reducing the size of G_vec_local and b_vec by taking the first iteration out of the
76 // loop can also be integrated.
77 for (size_t i = 0; i < log_poly_degree; i++) {
78 round_size >>= 1;
79 // Compute inner_prod_L := < a_vec_lo, b_vec_hi > and inner_prod_R := < a_vec_hi, b_vec_lo >
80 Fr inner_prod_L = Fr::zero();
81 Fr inner_prod_R = Fr::zero();
82 for (size_t j = 0; j < round_size; j++) {
83 inner_prod_L += a_vec[j] * b_vec[round_size + j];
84 inner_prod_R += a_vec[round_size + j] * b_vec[j];
85 }
86 // L_i = < a_vec_lo, G_vec_hi > + inner_prod_L * aux_generator
87 L_elements[i] =
88 // TODO(#473)
89 barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points<Curve>(
90 &a_vec[0], &G_vec_local[round_size], round_size, ck->pippenger_runtime_state);
91 L_elements[i] += aux_generator * inner_prod_L;
92
93 // R_i = < a_vec_hi, G_vec_lo > + inner_prod_R * aux_generator
94 // TODO(#473)
95 R_elements[i] = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points<Curve>(
96 &a_vec[round_size], &G_vec_local[0], round_size, ck->pippenger_runtime_state);
97 R_elements[i] += aux_generator * inner_prod_R;
98
99 std::string index = std::to_string(i);
100 transcript->send_to_verifier("IPA:L_" + index, Commitment(L_elements[i]));
101 transcript->send_to_verifier("IPA:R_" + index, Commitment(R_elements[i]));
102
103 // Generate the round challenge.
104 const Fr round_challenge = transcript->get_challenge("IPA:round_challenge_" + index);
105 const Fr round_challenge_inv = round_challenge.invert();
106
107 std::vector<Commitment> G_lo(G_vec_local.begin(), G_vec_local.begin() + static_cast<long>(round_size));
108 std::vector<Commitment> G_hi(G_vec_local.begin() + static_cast<long>(round_size), G_vec_local.end());
109 G_lo = GroupElement::batch_mul_with_endomorphism(G_lo, round_challenge_inv);
110 G_hi = GroupElement::batch_mul_with_endomorphism(G_hi, round_challenge);
111
112 // Update the vectors a_vec, b_vec and G_vec.
113 // a_vec_next = a_vec_lo * round_challenge + a_vec_hi * round_challenge_inv
114 // b_vec_next = b_vec_lo * round_challenge_inv + b_vec_hi * round_challenge
115 // G_vec_next = G_vec_lo * round_challenge_inv + G_vec_hi * round_challenge
116 for (size_t j = 0; j < round_size; j++) {
117 a_vec[j] *= round_challenge;
118 a_vec[j] += round_challenge_inv * a_vec[round_size + j];
119 b_vec[j] *= round_challenge_inv;
120 b_vec[j] += round_challenge * b_vec[round_size + j];
121
122 G_vec_local[j] = G_lo[j] + G_hi[j];
123 }
124 }
125
126 transcript->send_to_verifier("IPA:a_0", a_vec[0]);
127 }
128
138 static bool verify(const std::shared_ptr<VK>& vk,
139 const OpeningClaim<Curve>& opening_claim,
140 const std::shared_ptr<BaseTranscript>& transcript)
141 {
142 auto poly_degree = static_cast<size_t>(transcript->template receive_from_prover<uint64_t>("IPA:poly_degree"));
143 const Fr generator_challenge = transcript->get_challenge("IPA:generator_challenge");
144 auto aux_generator = Commitment::one() * generator_challenge;
145
146 auto log_poly_degree = static_cast<size_t>(numeric::get_msb(poly_degree));
147
148 // Compute C_prime
149 GroupElement C_prime = opening_claim.commitment + (aux_generator * opening_claim.opening_pair.evaluation);
150
151 // Compute C_zero = C_prime + ∑_{j ∈ [k]} u_j^2L_j + ∑_{j ∈ [k]} u_j^{-2}R_j
152 auto pippenger_size = 2 * log_poly_degree;
153 std::vector<Fr> round_challenges(log_poly_degree);
154 std::vector<Fr> round_challenges_inv(log_poly_degree);
155 std::vector<Commitment> msm_elements(pippenger_size);
156 std::vector<Fr> msm_scalars(pippenger_size);
157 for (size_t i = 0; i < log_poly_degree; i++) {
158 std::string index = std::to_string(i);
159 auto element_L = transcript->template receive_from_prover<Commitment>("IPA:L_" + index);
160 auto element_R = transcript->template receive_from_prover<Commitment>("IPA:R_" + index);
161 round_challenges[i] = transcript->get_challenge("IPA:round_challenge_" + index);
162 round_challenges_inv[i] = round_challenges[i].invert();
163
164 msm_elements[2 * i] = element_L;
165 msm_elements[2 * i + 1] = element_R;
166 msm_scalars[2 * i] = round_challenges[i].sqr();
167 msm_scalars[2 * i + 1] = round_challenges_inv[i].sqr();
168 }
169 // TODO(#473)
170 GroupElement LR_sums = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points<Curve>(
171 &msm_scalars[0], &msm_elements[0], pippenger_size, vk->pippenger_runtime_state);
172 GroupElement C_zero = C_prime + LR_sums;
173
181 Fr b_zero = Fr::one();
182 for (size_t i = 0; i < log_poly_degree; i++) {
183 auto exponent = static_cast<uint64_t>(Fr(2).pow(i));
184 b_zero *= round_challenges_inv[log_poly_degree - 1 - i] +
185 (round_challenges[log_poly_degree - 1 - i] * opening_claim.opening_pair.challenge.pow(exponent));
186 }
187
188 // Compute G_zero
189 // First construct s_vec
190 std::vector<Fr> s_vec(poly_degree);
191 for (size_t i = 0; i < poly_degree; i++) {
192 Fr s_vec_scalar = Fr::one();
193 for (size_t j = (log_poly_degree - 1); j != size_t(-1); j--) {
194 auto bit = (i >> j) & 1;
195 bool b = static_cast<bool>(bit);
196 if (b) {
197 s_vec_scalar *= round_challenges[log_poly_degree - 1 - j];
198 } else {
199 s_vec_scalar *= round_challenges_inv[log_poly_degree - 1 - j];
200 }
201 }
202 s_vec[i] = s_vec_scalar;
203 }
204 auto srs_elements = vk->srs->get_monomial_points();
205 // Copy the G_vector to local memory.
206 std::vector<Commitment> G_vec_local(poly_degree);
207 // The SRS stored in the commitment key is the result after applying the pippenger point table so the
208 // values at odd indices contain the point {srs[i-1].x * beta, srs[i-1].y}, where beta is the endomorphism
209 // G_vec_local should use only the original SRS thus we extract only the even indices.
210 for (size_t i = 0; i < poly_degree * 2; i += 2) {
211 G_vec_local[i >> 1] = srs_elements[i];
212 }
213 // TODO(#473)
214 auto G_zero = barretenberg::scalar_multiplication::pippenger_without_endomorphism_basis_points<Curve>(
215 &s_vec[0], &G_vec_local[0], poly_degree, vk->pippenger_runtime_state);
216
217 auto a_zero = transcript->template receive_from_prover<Fr>("IPA:a_0");
218
219 GroupElement right_hand_side = G_zero * a_zero + aux_generator * a_zero * b_zero;
220
221 return (C_zero.normalize() == right_hand_side.normalize());
222 }
223};
224
225} // namespace proof_system::honk::pcs::ipa
Definition: polynomial.hpp:12
CommitmentKey object over a pairing group 𝔾₁.
Definition: commitment_key.hpp:35
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition: claim.hpp:43
Opening pair (r,v) for some witness polynomial p(X) such that p(r) = v.
Definition: claim.hpp:12
Definition: verification_key.hpp:25
Definition: ipa.hpp:18
static bool verify(const std::shared_ptr< VK > &vk, const OpeningClaim< Curve > &opening_claim, const std::shared_ptr< BaseTranscript > &transcript)
Verify the correctness of a Proof.
Definition: ipa.hpp:138
static void compute_opening_proof(const std::shared_ptr< CK > &ck, const OpeningPair< Curve > &opening_pair, const Polynomial &polynomial, const std::shared_ptr< BaseTranscript > &transcript)
Compute an inner product argument proof for opening a single polynomial at a single evaluation point.
Definition: ipa.hpp:36
IPA (inner-product argument) commitment scheme class. Conforms to the specification https://hackmd....
Definition: ipa.hpp:17