We add a BatchedRelaxedR1CSSNARKTrait
which generalizes the existing RelaxedR1CSSNARKTrait
in src/traits/snark.rs
. The main difference is that the setup
, prove
and verify
methods take as inputs slices of
S
U
W
We also implement a CompressedSNARK
proof for the SuperNova RecursiveSNARK
. The main differences with the original are
BatchedRelaxedR1CSSNARK
.In src/spartan
, we implement batched versions of snark.rs
and pp_snark.rs
in batched.rs
and batched_ppsnark.rs
.
The BatchedRelaxedR1CSSNARK
structs in both cases resemble their non-batched counter-parts, except that fields containing commitments or evaluations are replaced with vectors of the same elements. The Sumcheck and PCS proofs are batched so their count remains constant with regards to the number of instances.
The proving/verification keys are also mainly the same, apart from having to store parameters for each individual circuit being proved.
The implementation attempts to mirror the existing SNARK and pp-SNARK as much as possible.
In the "IOP" portion of the protocol, where the prover sends commitments to polynomials or evaluations thereof, and the verifier responds with challenges, we simply repeat this step for each instance. The prover messages are added to the transcript in batches, and stored in the proof as vectors.
The Sumcheck claims are set up slightly differently to account for circuits of different sizes. In particular, when a claim of size is batched in a Sumcheck over rounds, we create separate EqPolynomials
for each instance. Given a single random challenge , we use the first components of to define the EqPolynomial
for a claim over variables. This ensures all polynomials within a claim have the same size. We explain in the next section how we modified Sumcheck to handle multiple claims of possibly different sizes.
Since the original SNARKs already implement batching of MLE evaluations, we are able to reuse the code to batch all polynomials across the several instances. We explain the subtleties of the batching argument for the ppSNARK in a later section.
Multiple Sumcheck claims can be batched together by running the protocol over a random-linear combination of the input claims. The existing implementation of ppSNARK already includes this functionality, though we augmented it to handle instances defined over fewer variables.
A Sumcheck instance implements the SumcheckEngine
trait. It may be composed of multiple independent claims of the type
where is a multivariate polynomial of degree , and are multi-linear polynomials in variables.
In rounds after receiving challenges , the prover computes for each claim the evaluations at of the univariate polynomial
The prover sends the random linear combination of all univariate polynomials and obtains the Fiat-Shamir challenge , which is used to bound the variable of the multilinear polynomials .
After the -th round, the prover sends equal to the multi-linear evaluations of at .
We can use the same Sumcheck instantiation to batch instances of different sizes.
Let be the number of variables for the instance
where are multi-linear polynomials over variables.
We can prove this claim with -round Sumcheck by considering the equivalent scaled instance
Here, we "lift" the -variate polynomials to variables by evaluating them over .
In rounds , the univariate polynomial is constant and given by
Given the initial claim , the prover produces the evaluations of without having to perform any work.
Moreover, binding the polynomials to has no effect, so we do not need to update the list of evaluations.
Once the prover reaches rounds , the protocol proceeds as usual. We note though that in the final phase, the prover sends the evaluations of the polynomials at .
In order to minimize the amount of changes to the existing ppsnark.rs
code, we implemented the above technique by recreating a prove_helper
method which handles batching of multiple instances of different sizes. Our changes are compatible with the existing Instances implementing the SumcheckEngine
trait.
The prove_helper
function takes as input multiple SumcheckEngine
implementations, each of which contains one or more independent claims. These claims hold over multilinear polynomials of the same size contained in the instance struct. It is assumed that all instances have degree 3. We let be the total number of Sumcheck rounds.
Let be a set of instances, where is defined by
For each instance at index and each sub-claim at index it holds that
At the start of the protocol, the verifier sends a challenge used for the random linear combination of claims. For notational simplicity, we define as the power of corresponding to the claim . The full batched claim is given by
The SumcheckProof::verify_batch
algorithm only considers the flattened list of claims
If the verifier accepts the final check, it must then check that all polynomial evaluations are correct.
Note that this batching technique implemented in the ppSNARK's prove_helper
method was also ported to the prove_quad_batch
and prove_cubic_with_additive_term_batch
methods of spartan::sumcheck::SumcheckProof
.
At the start of the protocol, the prover will have compute commitments to polynomials where is defined over variables. Again we let be the maximum number of variables.
We assume the PCS supports opening multilinear polynomials over variables. It is represented in memory by its list of evaluations which yields the expression
We commit to this polynomial by computing the MSM with the commitment key base points . That is
If a polynomial is defined over variables, it has evaluations . When committing to it, we interpret the evaluations at indices as zeros so that
This interpretation allows us to compute the MSM using only group operations.
Effectively, we have committed to the polynomial
During Sumcheck though, for polynomial defined over variables, we receive evaluations
In order to open using the commitment , we need to transform into an evaluation for the polynomial
For each evaluation provided by the Sumcheck prover, both parties compute a batched PCS evaluation instance and the prover computes the witness polynomial , such that
In the non-pre-processing SNARK, the verifier needs to verify the evaluations of multiple multi-linear polynomials at various points defined by the inner and outer Sumcheck instances. Unfortunately, the polynomial commitment schemes only support batching of evaluations for polynomials opened at the same point.
Since the creation of the opening argument is expensive, the original implementation uses a specialized Sumcheck argument to reduce each evaluation to an evaluation at a common point. All of these can be batched via random linear combination so that only a single PCS opening argument needs to be created.
Let be the maximum number of variables over all polynomials being opened. Let be a list of polynomial evaluation instances, where:
For each evaluation instance , the prover and verifier run the batched Sumcheck to prove the claim
The protocol proceeds as described in [[Compressed SNARK#Batched Sumcheck]], where all claims are appropriately scaled to variables.
The output is a query point and evaluations , to which we can apply the same technique as the [[Compressed SNARK#Batched PCS]].
The methods batch_eval_prove
and
batch_eval_verify
represent sub-protocols that reduce the task of checking the validity , to only checking the opening of a single evaluation instance .
In the pre-processing SNARK, the Sumcheck claims of each RelaxedR1CS instance are padded to . If we let , then the witness vector is of length , though we pad it to by adding zeros.
The public input is a list of at most elements, which we also consider as a MLE. These are appended to yielding the vector . Its MLE is given by:
The prover provides a commitment to by the verifier uses the values of and computations of the Lagrange polynomials to derive an evaluation of .
The evaluation of is performed over variables rather than the variables it is actually defined over. We need to ensure that does not "overflow" into the evaluation slots for , which we do using a new Sumcheck instance using a special MaskedEqPolynomial
.
This polynomial can be succinctly evaluated by noting that it is equal to
The Sumcheck instance we end up proving is
By definition of , the sum equals 0 (with overwhelming probability) since in the first entries, evaluates to 0 cancelling out the values of , while it equals in the remaining entries, forcing to be be 0.
We include this check as a separate SumcheckEngine
implementation, defined in spartan::batched_ppsnark::WitnessBoundSumcheck
. The constructor takes as input a random element , the maximum number of variables , and the padded witness . It computes the evaluations of , where .
One of the benefits of including this new instance is that the Sumcheck prover will have computed the multi-linear evaluation of , bypassing the need to compute it manually.