40 : p_(p), mc_(p.block_enc - p.dblock), tableau_(p.nrow * p.block_enc) {}
59 const Elt W[],
const size_t subfield_boundary,
61 const InterpolatorFactory &interpolator,
RandomEngine &rng,
64 for (
size_t i = 0; i < subfield_boundary; ++i) {
65 check(F.in_subfield(W[i]),
"element not in subfield");
68 layout(W, subfield_boundary, lqc, interpolator, rng, F);
71 auto updhash = [&](
size_t j,
SHA256 &sha) {
72 LigeroCommon<Field>::column_hash(p_.nrow, &tableau_at(0, j + p_.dblock),
73 p_.block_enc, sha, F);
75 commitment.root = mc_.commit(updhash, rng);
78 LigeroTranscript<Field>::write_commitment(commitment, ts);
89 const InterpolatorFactory &interpolator,
const Field &F) {
93 ts.write(hash_of_llterm.bytes, hash_of_llterm.kLength);
97 std::vector<Elt> u_ldt(p_.nwqrow);
100 LigeroTranscript<Field>::gen_uldt(&u_ldt[0], p_, ts, F);
101 low_degree_proof(&proof.y_ldt[0], &u_ldt[0], F);
105 std::vector<Elt> alphal(nl);
106 std::vector<std::array<Elt, 3>> alphaq(p_.nq);
107 std::vector<Elt> A(p_.nwqrow * p_.w);
110 LigeroTranscript<Field>::gen_alphal(nl, &alphal[0], ts, F);
111 LigeroTranscript<Field>::gen_alphaq(&alphaq[0], p_, ts, F);
113 LigeroCommon<Field>::inner_product_vector(&A[0], p_, nl, nllterm, llterm,
114 &alphal[0], lqc, &alphaq[0], F);
116 dot_proof(&proof.y_dot[0], &A[0], interpolator, F);
120 std::vector<Elt> u_quad(p_.nqtriples);
123 LigeroTranscript<Field>::gen_uquad(&u_quad[0], p_, ts, F);
124 quadratic_proof(&proof.y_quad_0[0], &proof.y_quad_2[0], &u_quad[0], F);
129 ts.write(&proof.y_ldt[0], 1, p_.block, F);
130 ts.write(&proof.y_dot[0], 1, p_.dblock, F);
131 ts.write(&proof.y_quad_0[0], 1, p_.r, F);
132 ts.write(&proof.y_quad_2[0], 1, p_.dblock - p_.block, F);
136 std::vector<size_t> idx(p_.nreq);
138 LigeroTranscript<Field>::gen_idx(&idx[0], p_, ts, F);
140 compute_req(proof, &idx[0]);
142 mc_.open(proof.merkle, &idx[0], p_.nreq);
147 Elt &tableau_at(
size_t i,
size_t j) {
148 size_t ld = p_.block_enc;
149 return tableau_[i * ld + j];
155 void random_row(
size_t i,
size_t n,
RandomEngine &rng,
const Field &F) {
156 for (
size_t j = 0; j < n; ++j) {
157 tableau_at(i, j) = rng.elt(F);
161 void random_subfield_row(
size_t i,
size_t n,
RandomEngine &rng,
163 for (
size_t j = 0; j < n; ++j) {
164 tableau_at(i, j) = rng.subfield_elt(F);
169 void layout_blinding_rows(
const InterpolatorFactory &interpolator,
173 const auto interp = interpolator.make(p_.block, p_.block_enc);
176 random_row(p_.ildt, p_.block, rng, F);
177 interp->interpolate(&tableau_at(p_.ildt, 0));
182 const auto interp = interpolator.make(p_.dblock, p_.block_enc);
186 random_row(p_.idot, p_.dblock, rng, F);
189 Elt sum = Blas<Field>::dot1(p_.w, &tableau_at(p_.idot, p_.r), 1, F);
190 F.sub(tableau_at(p_.idot, p_.r), sum);
192 interp->interpolate(&tableau_at(p_.idot, 0));
196 random_row(p_.iquad, p_.dblock, rng, F);
199 Blas<Field>::clear(p_.w, &tableau_at(p_.iquad, p_.r), 1, F);
201 interp->interpolate(&tableau_at(p_.iquad, 0));
205 void layout_witness_rows(
const Elt W[],
size_t subfield_boundary,
206 const InterpolatorFactory &interpolator,
208 const auto interp = interpolator.make(p_.block, p_.block_enc);
211 for (
size_t i = 0; i < p_.nwrow; ++i) {
213 bool subfield_only = ((i + 1) * p_.w <= subfield_boundary);
216 random_subfield_row(i + p_.iw, p_.r, rng, F);
218 random_row(i + p_.iw, p_.r, rng, F);
223 Blas<Field>::clear(p_.w, &tableau_at(i + p_.iw, p_.r), 1, F);
224 size_t max_col = std::min(p_.w, p_.nw - i * p_.w);
225 Blas<Field>::copy(max_col, &tableau_at(i + p_.iw, p_.r), 1, &W[i * p_.w],
227 interp->interpolate(&tableau_at(i + p_.iw, 0));
231 void layout_quadratic_rows(
const Elt W[],
233 const InterpolatorFactory &interpolator,
235 const auto interp = interpolator.make(p_.block, p_.block_enc);
239 size_t iqy = iqx + p_.nqtriples;
240 size_t iqz = iqy + p_.nqtriples;
242 for (
size_t i = 0; i < p_.nqtriples; ++i) {
243 random_row(iqx + i, p_.r, rng, F);
244 random_row(iqy + i, p_.r, rng, F);
245 random_row(iqz + i, p_.r, rng, F);
249 Blas<Field>::clear(p_.w, &tableau_at(iqx + i, p_.r), 1, F);
250 Blas<Field>::clear(p_.w, &tableau_at(iqy + i, p_.r), 1, F);
251 Blas<Field>::clear(p_.w, &tableau_at(iqz + i, p_.r), 1, F);
253 for (
size_t j = 0; j < p_.w && j + i * p_.w < p_.nq; ++j) {
254 const auto *l = &lqc[j + i * p_.w];
255 check(W[l->z] == F.mulf(W[l->x], W[l->y]),
256 "invalid quadratic constraints");
257 tableau_at(iqx + i, j + p_.r) = W[l->x];
258 tableau_at(iqy + i, j + p_.r) = W[l->y];
259 tableau_at(iqz + i, j + p_.r) = W[l->z];
261 interp->interpolate(&tableau_at(iqx + i, 0));
262 interp->interpolate(&tableau_at(iqy + i, 0));
263 interp->interpolate(&tableau_at(iqz + i, 0));
267 void layout(
const Elt W[],
size_t subfield_boundary,
269 const InterpolatorFactory &interpolator,
RandomEngine &rng,
271 layout_blinding_rows(interpolator, rng, F);
272 layout_witness_rows(W, subfield_boundary, interpolator, rng, F);
273 layout_quadratic_rows(W, lqc, interpolator, rng, F);
276 void low_degree_proof(Elt y[],
const Elt u_ldt[],
279 Blas<Field>::copy(p_.block, y, 1, &tableau_at(p_.ildt, 0), 1);
282 for (
size_t i = 0; i < p_.nwqrow; ++i) {
283 Blas<Field>::axpy(p_.block, y, 1, u_ldt[i], &tableau_at(i + p_.iw, 0), 1,
288 void dot_proof(Elt y[],
const Elt A[],
289 const InterpolatorFactory &interpolator,
const Field &F) {
290 const auto interpA = interpolator.make(p_.block, p_.dblock);
293 Blas<Field>::copy(p_.dblock, y, 1, &tableau_at(p_.idot, 0), 1);
295 std::vector<Elt> Aext(p_.dblock);
296 for (
size_t i = 0; i < p_.nwqrow; ++i) {
297 LigeroCommon<Field>::layout_Aext(&Aext[0], p_, i, &A[0], F);
298 interpA->interpolate(&Aext[0]);
301 Blas<Field>::vaxpy(p_.dblock, &y[0], 1, &Aext[0], 1,
302 &tableau_at(i + p_.iw, 0), 1, F);
306 void quadratic_proof(Elt y0[], Elt y2[],
307 const Elt u_quad[],
const Field &F) {
308 std::vector<Elt> y(p_.dblock);
309 std::vector<Elt> tmp(p_.dblock);
312 Blas<Field>::copy(p_.dblock, &y[0], 1, &tableau_at(p_.iquad, 0), 1);
315 size_t iqy = iqx + p_.nqtriples;
316 size_t iqz = iqy + p_.nqtriples;
318 for (
size_t i = 0; i < p_.nqtriples; ++i) {
322 Blas<Field>::copy(p_.dblock, &tmp[0], 1, &tableau_at(iqz + i, 0), 1);
325 Blas<Field>::vymax(p_.dblock, &tmp[0], 1, &tableau_at(iqx + i, 0), 1,
326 &tableau_at(iqy + i, 0), 1, F);
329 Blas<Field>::axpy(p_.dblock, &y[0], 1, u_quad[i], &tmp[0], 1, F);
333 bool ok = Blas<Field>::equal0(p_.w, &y[p_.r], 1, F);
334 check(ok,
"W part is nonzero");
337 Blas<Field>::copy(p_.r, y0, 1, &y[0], 1);
338 Blas<Field>::copy(p_.dblock - p_.block, y2, 1, &y[p_.block], 1);
342 for (
size_t i = 0; i < p_.nrow; ++i) {
343 Blas<Field>::gather(p_.nreq, &proof.req_at(i, 0),
344 &tableau_at(i, p_.dblock), idx);
350 std::vector<Elt> tableau_ ;