41 using inputs = std::vector<std::unique_ptr<Dense<Field>>>;
43 explicit ProverLayers(
const Field& f) : f_(f) {}
50 std::unique_ptr<Dense<Field>> eval_circuit(inputs* in,
54 if (in ==
nullptr || circ ==
nullptr || W0 ==
nullptr)
return nullptr;
56 std::unique_ptr<Dense<Field>> finalV;
57 size_t nl = circ->nl, nc = circ->nc;
58 check(nl >= 1,
"nl >= 1");
59 check(nc >= 1,
"nc >= 1");
64 in->at(nl - 1).swap(W0);
67 for (
size_t l = nl; l-- > 0;) {
71 in->at(l - 1) = std::make_unique<Dense<Field>>(nc, circ->l[l - 1].nw);
72 V = in->at(l - 1).get();
75 finalV = std::make_unique<Dense<Field>>(nc, circ->nv);
79 bool ok = eval_quad(circ->l[l].quad.get(), V, W, F);
84 for (
size_t i = 0; i < nl; ++i) {
106 Elt q[Proof<Field>::kMaxBindings];
107 Elt g[2][Proof<Field>::kMaxBindings];
115 size_t logc = circ->logc;
116 corner_t nc = circ->nc;
118 check(circ->logv <= Proof<Field>::kMaxBindings,
119 "CIRCUIT->logv <= kMaxBindings");
120 bnd.logv = circ->logv;
123 ts.begin_circuit(bnd.q, bnd.g[0]);
131 for (
size_t i = 0; i < bnd.logv; ++i) {
132 bnd.g[1][i] = bnd.g[0][i];
135 for (
size_t ly = 0; ly < circ->nl; ++ly) {
136 auto clr = &circ->l.at(ly);
138 ts.begin_layer(alpha, beta, ly);
140 auto QUAD = clr->quad->clone();
141 QUAD->bind_g(bnd.logv, bnd.g[0], bnd.g[1], alpha, beta, F);
143 layer(pr, pad, ts, bnd, ly, logc, clr->logw, &EQ, QUAD.get(),
146 if (aux !=
nullptr) {
147 aux->bound_quad[ly] = QUAD->scalar();
153 using index_t =
typename Quad<Field>::index_t;
154 using CPoly =
typename LayerProof<Field>::CPoly;
155 using WPoly =
typename LayerProof<Field>::WPoly;
169 void layer(Proof<Field>* pr,
const Proof<Field>* pad,
170 TranscriptSumcheck<Field>& ts,
bindings& bnd,
size_t layer,
171 size_t logc,
size_t logw, Eqs<Field>* EQ, Quad<Field>* QUAD,
172 Dense<Field>* W,
const Field& F) {
173 check(EQ->n() == W->n0_,
"EQ->n() == W->n0_");
175 check(logw <= Proof<Field>::kMaxBindings,
"logw <= kMaxBindings");
183 for (
size_t round = 0; round < logc; ++round) {
187 for (index_t i = 0; i < QUAD->n_; i++) {
188 corner_t r(QUAD->c_[i].h[0]);
189 corner_t l(QUAD->c_[i].h[1]);
195 for (corner_t c = 0; c < W->n0_; c += 2) {
196 CPoly poly = cpoly_at_dense(EQ, c, 0, F)
197 .mul(cpoly_at_dense(W, c, r, F), F)
198 .mul(cpoly_at_dense(W, c, l, F), F);
202 sumc.mul_scalar(QUAD->c_[i].v, F);
206 Elt rnd = round_c(pr, pad, ts, layer, round, sum, F);
214 Elt eq0 = EQ->scalar();
217 check(W->n1_ == 1,
"W->n1_ == 1");
219 auto Wclone = W->clone();
220 Dense<Field>* WH[2] = {W, Wclone.get()};
222 for (
size_t round = 0; round < logw; ++round) {
223 for (
size_t hand = 0; hand < 2; hand++) {
227 Dense<Field> QW(WH[hand]->n0_, 1);
229 size_t ohand = 1 - hand;
232 for (index_t i = 0; i < QUAD->n_; ++i) {
233 corner_t p0(QUAD->c_[i].h[hand]);
234 corner_t p1(QUAD->c_[i].h[ohand]);
235 F.add(QW.v_[p0], F.mulf(QUAD->c_[i].v, WH[ohand]->v_[p1]));
240 for (corner_t l = 0; l < QW.n0_; l += 2) {
241 WPoly poly = wpoly_at_dense(WH[hand], l, 0, F)
242 .mul(wpoly_at_dense(&QW, l, 0, F), F);
246 sum.mul_scalar(eq0, F);
247 Elt rnd = round_h(pr, pad, ts, layer, hand, round, sum, F);
248 bnd.g[hand][round] = rnd;
251 WH[hand]->bind(rnd, F);
252 QUAD->bind_h(rnd, hand, F);
257 Elt WC[2] = {WH[0]->scalar(), WH[1]->scalar()};
258 end_layer(pr, pad, ts, layer, WC, F);
266 bool eval_quad(
const Quad<Field>* quad, Dense<Field>* V,
267 const Dense<Field>* W,
const Field& F) {
268 check(V->n0_ == W->n0_,
"V->n0_ == W->n0_");
269 corner_t n0 = V->n0_;
272 for (index_t i = 0; i < quad->n_; i++) {
273 corner_t g(quad->c_[i].g);
274 corner_t r(quad->c_[i].h[0]);
275 corner_t l(quad->c_[i].h[1]);
276 for (corner_t c = 0; c < n0; ++c) {
277 auto x = quad->c_[i].v;
280 auto y = W->v_[n0 * l + c];
281 F.mul(y, W->v_[n0 * r + c]);
286 F.mul(x, W->v_[n0 * l + c]);
287 F.mul(x, W->v_[n0 * r + c]);
288 F.add(V->v_[n0 * g + c], x);
295 Elt round_c(Proof<Field>* pr,
const Proof<Field>* pad,
296 TranscriptSumcheck<Field>& ts,
size_t layer,
size_t round,
297 CPoly poly,
const Field& F) {
298 check(round <= Proof<Field>::kMaxBindings,
"round <= kMaxBindings");
301 poly.sub(pad->l[layer].cp[round], F);
304 pr->l[layer].cp[round] = poly;
305 return ts.round(poly);
308 Elt round_h(Proof<Field>* pr,
const Proof<Field>* pad,
309 TranscriptSumcheck<Field>& ts,
size_t layer,
size_t hand,
310 size_t round, WPoly poly,
const Field& F) {
311 check(round <= Proof<Field>::kMaxBindings,
"round <= kMaxBindings");
313 poly.sub(pad->l[layer].hp[hand][round], F);
315 pr->l[layer].hp[hand][round] = poly;
316 return ts.round(poly);
319 void end_layer(Proof<Field>* pr,
const Proof<Field>* pad,
320 TranscriptSumcheck<Field>& ts,
size_t layer,
const Elt wc[2],
322 Elt tt[2] = {wc[0], wc[1]};
324 F.sub(tt[0], pad->l[layer].wc[0]);
325 F.sub(tt[1], pad->l[layer].wc[1]);
328 pr->l[layer].wc[0] = tt[0];
329 pr->l[layer].wc[1] = tt[1];
334 CPoly cpoly_at_dense(
const Dense<Field>* D, corner_t p0, corner_t p1,
336 return CPoly::extend(D->t2_at_corners(p0, p1, F), F);
339 WPoly wpoly_at_dense(
const Dense<Field>* D, corner_t p0, corner_t p1,
341 return WPoly::extend(D->t2_at_corners(p0, p1, F), F);