41 using index_t =
typename Quad<Field>::index_t;
44 using CPoly =
typename LayerProof<Field>::CPoly;
45 using WPoly =
typename LayerProof<Field>::WPoly;
46 using FWPoly =
typename LayerProof<Field>::FWPoly;
50 static size_t verifier_constraints(
53 std::vector<Llc>& a, std::vector<typename Field::Elt>& b,
Transcript& tsv,
54 size_t pi,
const Field& F) {
55 const size_t ninp = circuit.ninputs, npub = circuit.npub_in;
60 tss.begin_circuit(ch.q, ch.g);
63 .claim = {F.zero(), F.zero()},
70 const typename FWPoly::dot_interpolation dot_wpoly(F);
73 check(circuit.logc == 0,
"assuming that copies=1");
76 for (
size_t ly = 0; ly < circuit.nl; ++ly) {
77 auto clr = &circuit.l.at(ly);
78 auto plr = &proof.l[ly];
79 auto challenge = &ch.l[ly];
81 tss.begin_layer(challenge->alpha, challenge->beta, ly);
84 check(clr->logw > 0,
"clr->logw > 0");
86 PadLayout pl(clr->logw);
87 ConstraintBuilder cb(pl, F);
89 cb.first(challenge->alpha, cla.claim);
92 for (
size_t round = 0; round < clr->logw; ++round) {
93 for (
size_t hand = 0; hand < 2; ++hand) {
94 size_t r = 2 * round + hand;
95 const WPoly& hp = plr->hp[hand][round];
96 challenge->hb[hand][round] = tss.round(hp);
97 const FWPoly lag = dot_wpoly.coef(challenge->hb[hand][round], F);
99 cb.next(r, &lag[0], hp.t_);
108 Elt quad = aux ==
nullptr ? bind_quad(clr, cla, challenge, F)
109 : aux->bound_quad[ly];
111 Eq<Field>::eval(circuit.logc, circuit.nc, ch.q, challenge->cb, F);
112 Elt eqq = F.mulf(eqv, quad);
115 cb.finalize(plr->wc, eqq, ci++, ly, pi, a, b);
117 tss.write(&plr->wc[0], 1, 2);
121 .claim = {plr->wc[0], plr->wc[1]},
123 .g = {challenge->hb[0], challenge->hb[1]},
126 pi += pl.layer_size();
132 Elt alpha = tsv.elt(F);
133 auto plr = &proof.l[circuit.nl - 1];
134 Elt got = F.addf(plr->wc[0], F.mulf(alpha, plr->wc[1]));
136 return input_constraint(cla, pub, npub, ninp, pi, got, alpha, a, b, ci, F);
142 for (
size_t i = 0; i < C.nl; ++i) {
143 PadLayout pl(C.l[i].logw);
144 sz += pl.layer_size();
151 std::vector<LigeroQuadraticConstraint>& lqc,
153 size_t pi = start_pad;
154 for (
size_t i = 0; i < C.nl; ++i) {
155 PadLayout pl(C.l[i].logw);
156 lqc[i].x = pi + pl.claim_pad(0);
157 lqc[i].y = pi + pl.claim_pad(1);
158 lqc[i].z = pi + pl.claim_pad(2);
159 pi += pl.layer_size();
164 static void initialize_sumcheck_fiat_shamir(
Transcript& ts,
168 ts.write(circuit.id,
sizeof(circuit.id));
171 for (
size_t i = 0; i < circuit.npub_in; ++i) {
172 ts.write(pub.at(i), F);
176 ts.write(F.zero(), F);
180 ts.write0(circuit.nterms());
198 explicit PadLayout(
size_t logw) : logw_(logw) {}
224 size_t poly_pad(
size_t r,
size_t point)
const {
225 check(point == 0 || point == 2,
"unknown poly_pad() layout");
228 }
else if (point == 2) {
234 size_t claim_pad(
size_t n)
const {
return poly_pad(2 * logw_, 0) + n; }
237 size_t layer_size()
const {
return claim_pad(3); }
243 size_t ovp_claim_pad_m1(
size_t n)
const {
return n; }
244 size_t ovp_poly_pad(
size_t r,
size_t point)
const {
245 return 3 + poly_pad(r, point);
247 size_t ovp_claim_pad(
size_t n)
const {
return 3 + claim_pad(n); }
248 size_t ovp_layer_size()
const {
return ovp_claim_pad(3); }
258 std::vector<Elt> symbolic_;
262 Expression(
size_t nvar,
const Field& F)
263 : known_(F.zero()), symbolic_(nvar, F.zero()), f_(F) {}
265 Elt known() {
return known_; }
266 std::vector<Elt> symbolic() {
return symbolic_; }
268 void scale(
const Elt& k) {
270 for (
auto& e : symbolic_) {
280 void axpy(
size_t var,
const Elt& known_value,
const Elt& k) {
281 f_.add(known_, f_.mulf(k, known_value));
282 f_.add(symbolic_[var], k);
286 void axmy(
size_t var,
const Elt& known_value,
const Elt& k) {
287 f_.sub(known_, f_.mulf(k, known_value));
288 f_.sub(symbolic_[var], k);
292 class ConstraintBuilder {
294 const PadLayout& pl_;
298 ConstraintBuilder(
const PadLayout& pl,
const Field& F)
299 : expr_(pl.ovp_layer_size(), F), pl_(pl), f_(F) {}
327 void first(Elt alpha,
const Elt claims[]) {
329 expr_.axpy(pl_.ovp_claim_pad_m1(0), claims[0], f_.one());
330 expr_.axpy(pl_.ovp_claim_pad_m1(1), claims[1], alpha);
335 void next(
size_t r,
const Elt lag[],
const Elt tr[]) {
337 expr_.axmy(pl_.ovp_poly_pad(r, 0), tr[0], f_.one());
345 expr_.axpy(pl_.ovp_poly_pad(r, 0), tr[0], lag[0]);
346 expr_.axpy(pl_.ovp_poly_pad(r, 2), tr[2], lag[2]);
374 void finalize(
const Elt wc[],
const Elt& eqq,
size_t ci,
size_t ly,
375 size_t pi, std::vector<Llc>& a, std::vector<Elt>& b) {
379 Elt rhs = f_.subf(f_.mulf(eqq, f_.mulf(wc[0], wc[1])), expr_.known());
382 std::vector<Elt> lhs = expr_.symbolic();
383 f_.sub(lhs[pl_.ovp_claim_pad(0)], f_.mulf(eqq, wc[1]));
384 f_.sub(lhs[pl_.ovp_claim_pad(1)], f_.mulf(eqq, wc[0]));
385 f_.sub(lhs[pl_.ovp_claim_pad(2)], eqq);
390 size_t i0 = (ly == 0) ? pl_.ovp_poly_pad(0, 0) : pl_.ovp_claim_pad_m1(0);
392 for (
size_t i = i0; i < lhs.size(); ++i) {
398 a.push_back(Llc{ci, (pi + i) - pl_.ovp_poly_pad(0, 0), lhs[i]});
407 static size_t input_constraint(
const Claims& cla,
const Dense<Field>& pub,
408 size_t pub_inputs,
size_t num_inputs,
409 size_t pi, Elt got, Elt alpha,
410 std::vector<Llc>& a, std::vector<Elt>& b,
411 size_t ci,
const Field& F) {
412 Eqs<Field> eq0(cla.logv, num_inputs, cla.g[0], F);
413 Eqs<Field> eq1(cla.logv, num_inputs, cla.g[1], F);
414 Elt pub_binding = F.zero();
415 for (index_t i = 0; i < num_inputs; ++i) {
416 Elt b_i = F.addf(eq0.at(i), F.mulf(alpha, eq1.at(i)));
417 if (i < pub_inputs) {
418 F.add(pub_binding, F.mulf(b_i, pub.at(i)));
421 a.push_back(Llc{ci, i - pub_inputs, b_i});
433 check(pi >= pl.ovp_poly_pad(0, 0),
"pi >= pl.ovp_poly_pad(0, 0)");
435 size_t claim_pad_m1 = pi - pl.ovp_poly_pad(0, 0);
436 a.push_back(Llc{ci, claim_pad_m1 + 0, F.mone()});
437 a.push_back(Llc{ci, claim_pad_m1 + 1, F.negf(alpha)});
438 b.push_back(F.subf(got, pub_binding));
442 static Elt bind_quad(
const Layer<Field>* clr,
const Claims& cla,
444 return clr->quad->bind_gh_all(
446 cla.logv, cla.g[0], cla.g[1], chal->alpha, chal->beta,
448 clr->logw, chal->hb[0], chal->hb[1],