41 using index_t =
typename Quad<Field>::index_t;
44 using CPoly =
typename LayerProof<Field>::CPoly;
45 using WPoly =
typename LayerProof<Field>::WPoly;
49 static size_t verifier_constraints(
52 std::vector<Llc>& a, std::vector<typename Field::Elt>& b,
Transcript& tsv,
53 size_t pi,
const Field& F) {
54 const size_t ninp = circuit.ninputs, npub = circuit.npub_in;
59 tss.begin_circuit(ch.q, ch.g);
62 .claim = {F.zero(), F.zero()},
69 const typename WPoly::dot_interpolation dot_wpoly(F);
72 check(circuit.logc == 0,
"assuming that copies=1");
75 for (
size_t ly = 0; ly < circuit.nl; ++ly) {
76 auto clr = &circuit.l.at(ly);
77 auto plr = &proof.l[ly];
78 auto challenge = &ch.l[ly];
80 tss.begin_layer(challenge->alpha, challenge->beta, ly);
83 check(clr->logw > 0,
"clr->logw > 0");
85 PadLayout pl(clr->logw);
86 ConstraintBuilder cb(pl, F);
88 cb.first(challenge->alpha, cla.claim);
91 for (
size_t round = 0; round < clr->logw; ++round) {
92 for (
size_t hand = 0; hand < 2; ++hand) {
93 size_t r = 2 * round + hand;
94 const WPoly& hp = plr->hp[hand][round];
95 challenge->hb[hand][round] = tss.round(hp);
96 const WPoly lag = dot_wpoly.coef(challenge->hb[hand][round], F);
98 cb.next(r, &lag[0], hp.t_);
107 Elt quad = aux ==
nullptr ? bind_quad(clr, cla, challenge, F)
108 : aux->bound_quad[ly];
110 Eq<Field>::eval(circuit.logc, circuit.nc, ch.q, challenge->cb, F);
111 Elt eqq = F.mulf(eqv, quad);
114 cb.finalize(plr->wc, eqq, ci++, ly, pi, a, b);
116 tss.write(&plr->wc[0], 1, 2);
120 .claim = {plr->wc[0], plr->wc[1]},
122 .g = {challenge->hb[0], challenge->hb[1]},
125 pi += pl.layer_size();
131 Elt alpha = tsv.elt(F);
132 auto plr = &proof.l[circuit.nl - 1];
133 Elt got = F.addf(plr->wc[0], F.mulf(alpha, plr->wc[1]));
135 return input_constraint(cla, pub, npub, ninp, pi, got, alpha, a, b, ci, F);
141 for (
size_t i = 0; i < C.nl; ++i) {
142 PadLayout pl(C.l[i].logw);
143 sz += pl.layer_size();
150 std::vector<LigeroQuadraticConstraint>& lqc,
152 size_t pi = start_pad;
153 for (
size_t i = 0; i < C.nl; ++i) {
154 PadLayout pl(C.l[i].logw);
155 lqc[i].x = pi + pl.claim_pad(0);
156 lqc[i].y = pi + pl.claim_pad(1);
157 lqc[i].z = pi + pl.claim_pad(2);
158 pi += pl.layer_size();
163 static void initialize_sumcheck_fiat_shamir(
Transcript& ts,
167 ts.write(circuit.id,
sizeof(circuit.id));
170 for (
size_t i = 0; i < circuit.npub_in; ++i) {
171 ts.write(pub.at(i), F);
175 ts.write(F.zero(), F);
179 ts.write0(circuit.nterms());
197 explicit PadLayout(
size_t logw) : logw_(logw) {}
223 size_t poly_pad(
size_t r,
size_t point)
const {
224 check(point == 0 || point == 2,
"unknown poly_pad() layout");
227 }
else if (point == 2) {
233 size_t claim_pad(
size_t n)
const {
return poly_pad(2 * logw_, 0) + n; }
236 size_t layer_size()
const {
return claim_pad(3); }
242 size_t ovp_claim_pad_m1(
size_t n)
const {
return n; }
243 size_t ovp_poly_pad(
size_t r,
size_t point)
const {
244 return 3 + poly_pad(r, point);
246 size_t ovp_claim_pad(
size_t n)
const {
return 3 + claim_pad(n); }
247 size_t ovp_layer_size()
const {
return ovp_claim_pad(3); }
257 std::vector<Elt> symbolic_;
261 Expression(
size_t nvar,
const Field& F)
262 : known_(F.zero()), symbolic_(nvar, F.zero()), f_(F) {}
264 Elt known() {
return known_; }
265 std::vector<Elt> symbolic() {
return symbolic_; }
267 void scale(
const Elt& k) {
269 for (
auto& e : symbolic_) {
279 void axpy(
size_t var,
const Elt& known_value,
const Elt& k) {
280 f_.add(known_, f_.mulf(k, known_value));
281 f_.add(symbolic_[var], k);
285 void axmy(
size_t var,
const Elt& known_value,
const Elt& k) {
286 f_.sub(known_, f_.mulf(k, known_value));
287 f_.sub(symbolic_[var], k);
291 class ConstraintBuilder {
293 const PadLayout& pl_;
297 ConstraintBuilder(
const PadLayout& pl,
const Field& F)
298 : expr_(pl.ovp_layer_size(), F), pl_(pl), f_(F) {}
326 void first(Elt alpha,
const Elt claims[]) {
328 expr_.axpy(pl_.ovp_claim_pad_m1(0), claims[0], f_.one());
329 expr_.axpy(pl_.ovp_claim_pad_m1(1), claims[1], alpha);
334 void next(
size_t r,
const Elt lag[],
const Elt tr[]) {
336 expr_.axmy(pl_.ovp_poly_pad(r, 0), tr[0], f_.one());
344 expr_.axpy(pl_.ovp_poly_pad(r, 0), tr[0], lag[0]);
345 expr_.axpy(pl_.ovp_poly_pad(r, 2), tr[2], lag[2]);
373 void finalize(
const Elt wc[],
const Elt& eqq,
size_t ci,
size_t ly,
374 size_t pi, std::vector<Llc>& a, std::vector<Elt>& b) {
378 Elt rhs = f_.subf(f_.mulf(eqq, f_.mulf(wc[0], wc[1])), expr_.known());
381 std::vector<Elt> lhs = expr_.symbolic();
382 f_.sub(lhs[pl_.ovp_claim_pad(0)], f_.mulf(eqq, wc[1]));
383 f_.sub(lhs[pl_.ovp_claim_pad(1)], f_.mulf(eqq, wc[0]));
384 f_.sub(lhs[pl_.ovp_claim_pad(2)], eqq);
389 size_t i0 = (ly == 0) ? pl_.ovp_poly_pad(0, 0) : pl_.ovp_claim_pad_m1(0);
391 for (
size_t i = i0; i < lhs.size(); ++i) {
397 a.push_back(Llc{ci, (pi + i) - pl_.ovp_poly_pad(0, 0), lhs[i]});
406 static size_t input_constraint(
const Claims& cla,
const Dense<Field>& pub,
407 size_t pub_inputs,
size_t num_inputs,
408 size_t pi, Elt got, Elt alpha,
409 std::vector<Llc>& a, std::vector<Elt>& b,
410 size_t ci,
const Field& F) {
411 Eqs<Field> eq0(cla.logv, num_inputs, cla.g[0], F);
412 Eqs<Field> eq1(cla.logv, num_inputs, cla.g[1], F);
413 Elt pub_binding = F.zero();
414 for (index_t i = 0; i < num_inputs; ++i) {
415 Elt b_i = F.addf(eq0.at(i), F.mulf(alpha, eq1.at(i)));
416 if (i < pub_inputs) {
417 F.add(pub_binding, F.mulf(b_i, pub.at(i)));
420 a.push_back(Llc{ci, i - pub_inputs, b_i});
432 check(pi >= pl.ovp_poly_pad(0, 0),
"pi >= pl.ovp_poly_pad(0, 0)");
434 size_t claim_pad_m1 = pi - pl.ovp_poly_pad(0, 0);
435 a.push_back(Llc{ci, claim_pad_m1 + 0, F.mone()});
436 a.push_back(Llc{ci, claim_pad_m1 + 1, F.negf(alpha)});
437 b.push_back(F.subf(got, pub_binding));
441 static Elt bind_quad(
const Layer<Field>* clr,
const Claims& cla,
443 return clr->quad->bind_gh_all(
445 cla.logv, cla.g[0], cla.g[1], chal->alpha, chal->beta,
447 clr->logw, chal->hb[0], chal->hb[1],