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;
156 using FCPoly =
typename LayerProof<Field>::FCPoly;
157 using FWPoly =
typename LayerProof<Field>::FWPoly;
171 void layer(Proof<Field>* pr,
const Proof<Field>* pad,
172 TranscriptSumcheck<Field>& ts,
bindings& bnd,
size_t layer,
173 size_t logc,
size_t logw, Eqs<Field>* EQ, Quad<Field>* QUAD,
174 Dense<Field>* W,
const Field& F) {
175 check(EQ->n() == W->n0_,
"EQ->n() == W->n0_");
177 check(logw <= Proof<Field>::kMaxBindings,
"logw <= kMaxBindings");
185 for (
size_t round = 0; round < logc; ++round) {
189 for (index_t i = 0; i < QUAD->n_; i++) {
190 corner_t r(QUAD->c_[i].h[0]);
191 corner_t l(QUAD->c_[i].h[1]);
197 for (corner_t c = 0; c < W->n0_; c += 2) {
198 CPoly poly = cpoly_at_dense(EQ, c, 0, F)
199 .mul(cpoly_at_dense(W, c, r, F), F)
200 .mul(cpoly_at_dense(W, c, l, F), F);
204 sumc.mul_scalar(QUAD->c_[i].v, F);
208 Elt rnd = round_c(pr, pad, ts, layer, round, sum, F);
216 Elt eq0 = EQ->scalar();
219 check(W->n1_ == 1,
"W->n1_ == 1");
221 auto Wclone = W->clone();
222 Dense<Field>* WH[2] = {W, Wclone.get()};
224 for (
size_t round = 0; round < logw; ++round) {
225 for (
size_t hand = 0; hand < 2; hand++) {
229 Dense<Field> QW(WH[hand]->n0_, 1);
231 size_t ohand = 1 - hand;
234 for (index_t i = 0; i < QUAD->n_; ++i) {
235 corner_t p0(QUAD->c_[i].h[hand]);
236 corner_t p1(QUAD->c_[i].h[ohand]);
237 F.add(QW.v_[p0], F.mulf(QUAD->c_[i].v, WH[ohand]->v_[p1]));
242 for (corner_t l = 0; l < QW.n0_; l += 2) {
243 WPoly poly = wpoly_at_dense(WH[hand], l, 0, F)
244 .mul(wpoly_at_dense(&QW, l, 0, F), F);
248 sum.mul_scalar(eq0, F);
249 Elt rnd = round_h(pr, pad, ts, layer, hand, round, sum, F);
250 bnd.g[hand][round] = rnd;
253 WH[hand]->bind(rnd, F);
254 QUAD->bind_h(rnd, hand, F);
259 Elt WC[2] = {WH[0]->scalar(), WH[1]->scalar()};
260 end_layer(pr, pad, ts, layer, WC, F);
268 bool eval_quad(
const Quad<Field>* quad, Dense<Field>* V,
269 const Dense<Field>* W,
const Field& F) {
270 check(V->n0_ == W->n0_,
"V->n0_ == W->n0_");
271 corner_t n0 = V->n0_;
274 for (index_t i = 0; i < quad->n_; i++) {
275 corner_t g(quad->c_[i].g);
276 corner_t r(quad->c_[i].h[0]);
277 corner_t l(quad->c_[i].h[1]);
278 for (corner_t c = 0; c < n0; ++c) {
279 auto x = quad->c_[i].v;
282 auto y = W->v_[n0 * l + c];
283 F.mul(y, W->v_[n0 * r + c]);
288 F.mul(x, W->v_[n0 * l + c]);
289 F.mul(x, W->v_[n0 * r + c]);
290 F.add(V->v_[n0 * g + c], x);
297 Elt round_c(Proof<Field>* pr,
const Proof<Field>* pad,
298 TranscriptSumcheck<Field>& ts,
size_t layer,
size_t round,
299 CPoly poly,
const Field& F) {
300 check(round <= Proof<Field>::kMaxBindings,
"round <= kMaxBindings");
303 poly.sub(pad->l[layer].cp[round], F);
306 pr->l[layer].cp[round] = poly;
307 return ts.round(poly);
310 Elt round_h(Proof<Field>* pr,
const Proof<Field>* pad,
311 TranscriptSumcheck<Field>& ts,
size_t layer,
size_t hand,
312 size_t round, WPoly poly,
const Field& F) {
313 check(round <= Proof<Field>::kMaxBindings,
"round <= kMaxBindings");
315 poly.sub(pad->l[layer].hp[hand][round], F);
317 pr->l[layer].hp[hand][round] = poly;
318 return ts.round(poly);
321 void end_layer(Proof<Field>* pr,
const Proof<Field>* pad,
322 TranscriptSumcheck<Field>& ts,
size_t layer,
const Elt wc[2],
324 Elt tt[2] = {wc[0], wc[1]};
326 F.sub(tt[0], pad->l[layer].wc[0]);
327 F.sub(tt[1], pad->l[layer].wc[1]);
330 pr->l[layer].wc[0] = tt[0];
331 pr->l[layer].wc[1] = tt[1];
336 CPoly cpoly_at_dense(
const Dense<Field>* D, corner_t p0, corner_t p1,
338 auto tmp = FCPoly::extend(D->t2_at_corners(p0, p1, F), F);
342 WPoly wpoly_at_dense(
const Dense<Field>* D, corner_t p0, corner_t p1,
344 auto tmp = FWPoly::extend(D->t2_at_corners(p0, p1, F), F);