zorch.spartan.r1cs¶
R1CS instance (A·z) ∘ (B·z) = C·z and the products the Spartan PIOP reduces.
The assignment is witness-first z = (W, 1, X): W fills the low half, the
high half holds the constant 1 then the public inputs X. That layout is what
makes r_y[0] (the inner sumcheck's first-bound variable) the half-selector
between W and (1, X), so W opens at r_y[1:]. Matrices are dense (a sparse
SPARK form would plug the same matvecs / combined-row interface). Field is the
caller's dtype.
R1CS
dataclass
¶
A dense R1CS instance (A·z) ∘ (B·z) = C·z.
a, b, c are (m, n) dense matrices over the field; m = num_cons is a
power of two and n = 2·num_vars_padded is a power of two with the witness in
the low half (z = (W, 1, X)). num_io is the public-input count. The class
holds no witness — an assignment z is passed to the product helpers, so one
instance serves many assignments.
Source code in zorch/spartan/r1cs.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
matvecs ¶
matvecs(z: Array) -> tuple[Array, Array, Array]
(A·z, B·z, C·z), each length num_cons — the outer-sumcheck MLEs.
Source code in zorch/spartan/r1cs.py
74 75 76 | |
is_satisfied ¶
is_satisfied(z: Array) -> Array
Row-wise (A·z)∘(B·z) == C·z for all rows (scalar bool).
Source code in zorch/spartan/r1cs.py
78 79 80 81 | |
combined_row_mle ¶
combined_row_mle(r_x: Array, r_batch: Array) -> Array
M(y) = Σ_i eq(r_x)_i · (A + r·B + r²·C)_{i,y}, length num_cols.
The inner-sumcheck operand: the three matrices batched by powers of r,
then bound on the row variables at r_x. MSB-first row order matches the
outer sumcheck's bind and expand_eq_to_hypercube.
Source code in zorch/spartan/r1cs.py
83 84 85 86 87 88 89 90 91 92 | |
eval_combined_matrix ¶
eval_combined_matrix(
r_x: Array, r_y: Array, r_batch: Array
) -> Array
Ã(r_x,r_y) + r·B̃ + r²·C̃ as eq(r_x)·M·eq(r_y) — the verifier's
eval_ABC. Dense here; a succinct scheme opens it from a SPARK commitment.
Source code in zorch/spartan/r1cs.py
94 95 96 97 98 99 100 101 | |
eval_eq ¶
eval_eq(w: Array, x: Array) -> Array
eq(w, x) = Π_i (1 - w_i - x_i + 2·w_i·x_i) for two equal-length points, in O(len) time and O(1) memory.
The closed form of the equality polynomial evaluated at a pair of points --
equals (expand_eq_to_hypercube(x, 1) · expand_eq_to_hypercube(w, 1)).sum()
but without materializing either 2^len vector, so a verifier evaluating eq at
a bound point stays succinct. Symmetric in w/x and order-agnostic (a
product over coordinates), so MSB/LSB indexing does not matter.
Source code in zorch/poly/eq.py
43 44 45 46 47 48 49 50 51 52 | |
assignment ¶
assignment(
witness: Array,
io: Array,
num_vars_padded: int,
num_io: int,
) -> Array
Assemble z = (W, 1, X) from the witness and public inputs.
W is padded into the low half [0, num_vars_padded); the high half holds
the constant 1 at its first slot, then the public inputs X, then zero
padding. Length is 2·num_vars_padded.
Source code in zorch/spartan/r1cs.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
eval_public_half ¶
eval_public_half(
io: Array, r_y_rest: Array, num_vars_padded: int
) -> Array
MLE of the public high half (1, X, 0…) at r_y[1:].
The verifier evaluates the (1, X) part of z̃ itself; combined with the
witness opening eval_W it reconstructs z̃(r_y) — see pcs_glue.
Source code in zorch/spartan/r1cs.py
122 123 124 125 126 127 128 129 130 131 | |
recombine_z_eval ¶
recombine_z_eval(
eval_w: Array, eval_pub: Array, r_y0: Array
) -> Array
z̃(r_y) from the two half-openings: (1−r_y0)·eval_W + r_y0·eval_pub.
r_y0 (the MSB inner challenge) selects between the witness low half and the
public high half; the multilinear bind on that top variable is this affine
combination.
Source code in zorch/spartan/r1cs.py
134 135 136 137 138 139 140 141 142 | |