2020-11-13 00:08:08 +00:00
|
|
|
use ff::Field;
|
2020-10-21 21:17:23 +00:00
|
|
|
use std::iter;
|
|
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
use super::{
|
2020-11-06 03:25:50 +00:00
|
|
|
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
|
2020-11-25 00:49:52 +00:00
|
|
|
permutation, Error, Proof, ProvingKey,
|
2020-08-22 20:15:39 +00:00
|
|
|
};
|
|
|
|
|
use crate::arithmetic::{
|
2020-11-25 00:49:52 +00:00
|
|
|
eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, FieldExt,
|
2020-08-22 20:15:39 +00:00
|
|
|
};
|
2020-09-07 16:22:25 +00:00
|
|
|
use crate::poly::{
|
2020-09-29 07:23:41 +00:00
|
|
|
commitment::{Blind, Params},
|
2020-10-07 16:13:06 +00:00
|
|
|
multiopen::{self, ProverQuery},
|
2020-11-25 00:49:52 +00:00
|
|
|
LagrangeCoeff, Polynomial,
|
2020-09-07 16:22:25 +00:00
|
|
|
};
|
2020-10-14 23:35:06 +00:00
|
|
|
use crate::transcript::{Hasher, Transcript};
|
2020-08-22 20:15:39 +00:00
|
|
|
|
|
|
|
|
impl<C: CurveAffine> Proof<C> {
|
|
|
|
|
/// This creates a proof for the provided `circuit` when given the public
|
2020-09-29 14:25:04 +00:00
|
|
|
/// parameters `params` and the proving key [`ProvingKey`] that was
|
|
|
|
|
/// generated previously for the same circuit.
|
2020-08-22 20:15:39 +00:00
|
|
|
pub fn create<
|
|
|
|
|
HBase: Hasher<C::Base>,
|
|
|
|
|
HScalar: Hasher<C::Scalar>,
|
|
|
|
|
ConcreteCircuit: Circuit<C::Scalar>,
|
|
|
|
|
>(
|
|
|
|
|
params: &Params<C>,
|
2020-09-29 14:25:04 +00:00
|
|
|
pk: &ProvingKey<C>,
|
2020-08-22 20:15:39 +00:00
|
|
|
circuit: &ConcreteCircuit,
|
2020-09-19 19:31:56 +00:00
|
|
|
aux: &[Polynomial<C::Scalar, LagrangeCoeff>],
|
2020-08-22 20:15:39 +00:00
|
|
|
) -> Result<Self, Error> {
|
2020-11-06 03:13:54 +00:00
|
|
|
if aux.len() != pk.vk.cs.num_aux_columns {
|
2020-09-19 19:31:56 +00:00
|
|
|
return Err(Error::IncompatibleParams);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
struct WitnessCollection<F: Field> {
|
2020-09-07 16:22:25 +00:00
|
|
|
advice: Vec<Polynomial<F, LagrangeCoeff>>,
|
|
|
|
|
_marker: std::marker::PhantomData<F>,
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
2020-09-11 23:18:41 +00:00
|
|
|
impl<F: Field> Assignment<F> for WitnessCollection<F> {
|
2020-08-23 19:26:04 +00:00
|
|
|
fn assign_advice(
|
2020-08-22 22:10:27 +00:00
|
|
|
&mut self,
|
2020-11-06 03:25:50 +00:00
|
|
|
column: Column<Advice>,
|
2020-08-23 19:26:04 +00:00
|
|
|
row: usize,
|
2020-08-22 22:10:27 +00:00
|
|
|
to: impl FnOnce() -> Result<F, Error>,
|
|
|
|
|
) -> Result<(), Error> {
|
2020-08-23 19:26:04 +00:00
|
|
|
*self
|
|
|
|
|
.advice
|
2020-11-09 16:45:52 +00:00
|
|
|
.get_mut(column.index())
|
2020-08-23 19:26:04 +00:00
|
|
|
.and_then(|v| v.get_mut(row))
|
|
|
|
|
.ok_or(Error::BoundsFailure)? = to()?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn assign_fixed(
|
|
|
|
|
&mut self,
|
2020-11-06 03:25:50 +00:00
|
|
|
_: Column<Fixed>,
|
2020-08-23 19:26:04 +00:00
|
|
|
_: usize,
|
|
|
|
|
_: impl FnOnce() -> Result<F, Error>,
|
|
|
|
|
) -> Result<(), Error> {
|
2020-11-06 03:13:54 +00:00
|
|
|
// We only care about advice columns here
|
2020-08-23 19:26:04 +00:00
|
|
|
|
2020-08-22 22:10:27 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
2020-08-31 05:58:00 +00:00
|
|
|
|
2020-08-31 16:01:09 +00:00
|
|
|
fn copy(
|
|
|
|
|
&mut self,
|
|
|
|
|
_: usize,
|
|
|
|
|
_: usize,
|
|
|
|
|
_: usize,
|
|
|
|
|
_: usize,
|
|
|
|
|
_: usize,
|
|
|
|
|
) -> Result<(), Error> {
|
2020-11-06 03:13:54 +00:00
|
|
|
// We only care about advice columns here
|
2020-08-31 05:58:00 +00:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
2020-09-29 14:25:04 +00:00
|
|
|
let domain = &pk.vk.domain;
|
2020-09-11 23:18:41 +00:00
|
|
|
let mut meta = ConstraintSystem::default();
|
2020-08-22 22:10:27 +00:00
|
|
|
let config = ConcreteCircuit::configure(&mut meta);
|
|
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
let mut witness = WitnessCollection {
|
2020-11-06 03:13:54 +00:00
|
|
|
advice: vec![domain.empty_lagrange(); meta.num_advice_columns],
|
2020-09-07 16:22:25 +00:00
|
|
|
_marker: std::marker::PhantomData,
|
2020-08-22 20:15:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Synthesize the circuit to obtain the witness and other information.
|
2020-08-22 21:09:47 +00:00
|
|
|
circuit.synthesize(&mut witness, config)?;
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2020-09-07 15:37:49 +00:00
|
|
|
let witness = witness;
|
|
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
// Create a transcript for obtaining Fiat-Shamir challenges.
|
2020-10-14 23:35:06 +00:00
|
|
|
let mut transcript = Transcript::<C, HBase, HScalar>::new();
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
// Compute commitments to aux column polynomials
|
2020-09-19 19:31:56 +00:00
|
|
|
let aux_commitments_projective: Vec<_> = aux
|
|
|
|
|
.iter()
|
2020-09-25 15:28:49 +00:00
|
|
|
.map(|poly| params.commit_lagrange(poly, Blind::default()))
|
2020-09-19 19:31:56 +00:00
|
|
|
.collect();
|
|
|
|
|
let mut aux_commitments = vec![C::zero(); aux_commitments_projective.len()];
|
|
|
|
|
C::Projective::batch_to_affine(&aux_commitments_projective, &mut aux_commitments);
|
|
|
|
|
let aux_commitments = aux_commitments;
|
|
|
|
|
drop(aux_commitments_projective);
|
2020-11-23 15:35:50 +00:00
|
|
|
metrics::counter!("aux_commitments", aux_commitments.len() as u64);
|
2020-09-19 19:31:56 +00:00
|
|
|
|
|
|
|
|
for commitment in &aux_commitments {
|
2020-10-15 09:01:26 +00:00
|
|
|
transcript
|
|
|
|
|
.absorb_point(commitment)
|
|
|
|
|
.map_err(|_| Error::TranscriptError)?;
|
2020-09-19 19:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let aux_polys: Vec<_> = aux
|
2020-09-20 19:09:03 +00:00
|
|
|
.iter()
|
2020-09-19 19:31:56 +00:00
|
|
|
.map(|poly| {
|
|
|
|
|
let lagrange_vec = domain.lagrange_from_vec(poly.to_vec());
|
|
|
|
|
domain.lagrange_to_coeff(lagrange_vec)
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
let aux_cosets: Vec<_> = meta
|
|
|
|
|
.aux_queries
|
|
|
|
|
.iter()
|
2020-11-06 03:13:54 +00:00
|
|
|
.map(|&(column, at)| {
|
2020-11-09 16:45:52 +00:00
|
|
|
let poly = aux_polys[column.index()].clone();
|
2020-09-19 19:31:56 +00:00
|
|
|
domain.coeff_to_extended(poly, at)
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
// Compute commitments to advice column polynomials
|
2020-09-07 16:22:25 +00:00
|
|
|
let advice_blinds: Vec<_> = witness
|
|
|
|
|
.advice
|
|
|
|
|
.iter()
|
2020-11-13 00:08:08 +00:00
|
|
|
.map(|_| Blind(C::Scalar::rand()))
|
2020-09-07 16:22:25 +00:00
|
|
|
.collect();
|
2020-09-06 18:24:55 +00:00
|
|
|
let advice_commitments_projective: Vec<_> = witness
|
2020-08-22 22:10:27 +00:00
|
|
|
.advice
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(advice_blinds.iter())
|
2020-09-06 18:24:55 +00:00
|
|
|
.map(|(poly, blind)| params.commit_lagrange(poly, *blind))
|
2020-08-22 22:10:27 +00:00
|
|
|
.collect();
|
2020-09-06 18:24:55 +00:00
|
|
|
let mut advice_commitments = vec![C::zero(); advice_commitments_projective.len()];
|
|
|
|
|
C::Projective::batch_to_affine(&advice_commitments_projective, &mut advice_commitments);
|
|
|
|
|
let advice_commitments = advice_commitments;
|
|
|
|
|
drop(advice_commitments_projective);
|
2020-11-10 23:59:06 +00:00
|
|
|
metrics::counter!("advice_commitments", advice_commitments.len() as u64);
|
2020-08-22 22:10:27 +00:00
|
|
|
|
|
|
|
|
for commitment in &advice_commitments {
|
2020-10-15 09:01:26 +00:00
|
|
|
transcript
|
|
|
|
|
.absorb_point(commitment)
|
|
|
|
|
.map_err(|_| Error::TranscriptError)?;
|
2020-08-22 22:10:27 +00:00
|
|
|
}
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2020-08-22 22:10:27 +00:00
|
|
|
let advice_polys: Vec<_> = witness
|
|
|
|
|
.advice
|
2020-09-03 16:58:48 +00:00
|
|
|
.clone()
|
2020-08-22 22:10:27 +00:00
|
|
|
.into_iter()
|
2020-09-07 16:22:25 +00:00
|
|
|
.map(|poly| domain.lagrange_to_coeff(poly))
|
2020-08-22 22:10:27 +00:00
|
|
|
.collect();
|
|
|
|
|
|
2020-08-27 16:10:55 +00:00
|
|
|
let advice_cosets: Vec<_> = meta
|
|
|
|
|
.advice_queries
|
2020-08-22 20:15:39 +00:00
|
|
|
.iter()
|
2020-11-06 03:13:54 +00:00
|
|
|
.map(|&(column, at)| {
|
2020-11-09 16:45:52 +00:00
|
|
|
let poly = advice_polys[column.index()].clone();
|
2020-09-07 16:22:25 +00:00
|
|
|
domain.coeff_to_extended(poly, at)
|
2020-08-27 16:10:55 +00:00
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2020-09-01 05:06:25 +00:00
|
|
|
// Sample x_0 challenge
|
|
|
|
|
let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
|
|
|
|
|
|
|
|
|
// Sample x_1 challenge
|
|
|
|
|
let x_1: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
|
|
|
|
|
2020-11-25 00:49:52 +00:00
|
|
|
// Commit to permutations, if any.
|
|
|
|
|
let permutations = if !pk.vk.cs.permutations.is_empty() {
|
|
|
|
|
Some(permutation::Proof::commit(
|
|
|
|
|
params,
|
|
|
|
|
pk,
|
|
|
|
|
&witness.advice,
|
|
|
|
|
x_0,
|
|
|
|
|
x_1,
|
|
|
|
|
&mut transcript,
|
|
|
|
|
)?)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2020-09-03 16:58:48 +00:00
|
|
|
|
2020-08-27 16:10:55 +00:00
|
|
|
// Obtain challenge for keeping all separate gates linearly independent
|
|
|
|
|
let x_2: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
|
|
|
|
|
2020-11-25 00:49:52 +00:00
|
|
|
// Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any.
|
|
|
|
|
let (permutations, permutation_expressions) = permutations
|
|
|
|
|
.map(|p| p.construct(pk, &advice_cosets, x_0, x_1))
|
|
|
|
|
.transpose()?
|
|
|
|
|
.map(|(p, expressions)| (Some(p), Some(expressions)))
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
2020-11-24 23:38:26 +00:00
|
|
|
// Evaluate the h(X) polynomial's constraint system expressions for the constraints provided
|
2020-11-25 00:49:52 +00:00
|
|
|
let h_poly = iter::empty()
|
|
|
|
|
// Custom constraints
|
|
|
|
|
.chain(meta.gates.iter().map(|poly| {
|
|
|
|
|
poly.evaluate(
|
|
|
|
|
&|index| pk.fixed_cosets[index].clone(),
|
|
|
|
|
&|index| advice_cosets[index].clone(),
|
|
|
|
|
&|index| aux_cosets[index].clone(),
|
|
|
|
|
&|a, b| a + &b,
|
|
|
|
|
&|a, b| a * &b,
|
|
|
|
|
&|a, scalar| a * scalar,
|
2020-11-24 23:38:26 +00:00
|
|
|
)
|
2020-11-25 00:49:52 +00:00
|
|
|
}))
|
|
|
|
|
// Permutation constraints, if any.
|
|
|
|
|
.chain(permutation_expressions.into_iter().flatten())
|
|
|
|
|
.fold(domain.empty_extended(), |h_poly, v| h_poly * x_2 + &v);
|
2020-09-03 23:21:44 +00:00
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
// Divide by t(X) = X^{params.n} - 1.
|
|
|
|
|
let h_poly = domain.divide_by_vanishing_poly(h_poly);
|
|
|
|
|
|
|
|
|
|
// Obtain final h(X) polynomial
|
2020-09-07 16:22:25 +00:00
|
|
|
let h_poly = domain.extended_to_coeff(h_poly);
|
2020-08-22 20:15:39 +00:00
|
|
|
|
|
|
|
|
// Split h(X) up into pieces
|
|
|
|
|
let h_pieces = h_poly
|
|
|
|
|
.chunks_exact(params.n as usize)
|
2020-09-07 16:22:25 +00:00
|
|
|
.map(|v| domain.coeff_from_vec(v.to_vec()))
|
2020-08-22 20:15:39 +00:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
drop(h_poly);
|
2020-11-13 00:08:08 +00:00
|
|
|
let h_blinds: Vec<_> = h_pieces.iter().map(|_| Blind(C::Scalar::rand())).collect();
|
2020-08-22 20:15:39 +00:00
|
|
|
|
|
|
|
|
// Compute commitments to each h(X) piece
|
2020-09-06 18:24:55 +00:00
|
|
|
let h_commitments_projective: Vec<_> = h_pieces
|
2020-08-22 20:15:39 +00:00
|
|
|
.iter()
|
|
|
|
|
.zip(h_blinds.iter())
|
2020-09-06 18:24:55 +00:00
|
|
|
.map(|(h_piece, blind)| params.commit(&h_piece, *blind))
|
2020-08-22 20:15:39 +00:00
|
|
|
.collect();
|
2020-09-06 18:24:55 +00:00
|
|
|
let mut h_commitments = vec![C::zero(); h_commitments_projective.len()];
|
|
|
|
|
C::Projective::batch_to_affine(&h_commitments_projective, &mut h_commitments);
|
|
|
|
|
let h_commitments = h_commitments;
|
|
|
|
|
drop(h_commitments_projective);
|
2020-08-22 20:15:39 +00:00
|
|
|
|
|
|
|
|
// Hash each h(X) piece
|
|
|
|
|
for c in h_commitments.iter() {
|
2020-10-15 09:01:26 +00:00
|
|
|
transcript
|
|
|
|
|
.absorb_point(c)
|
|
|
|
|
.map_err(|_| Error::TranscriptError)?;
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
2020-08-27 16:10:55 +00:00
|
|
|
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
|
|
|
|
|
|
|
|
|
// Evaluate polynomials at omega^i x_3
|
2020-08-27 16:25:36 +00:00
|
|
|
let advice_evals: Vec<_> = meta
|
2020-08-27 16:10:55 +00:00
|
|
|
.advice_queries
|
|
|
|
|
.iter()
|
2020-11-06 03:13:54 +00:00
|
|
|
.map(|&(column, at)| {
|
2020-11-09 16:45:52 +00:00
|
|
|
eval_polynomial(&advice_polys[column.index()], domain.rotate_omega(x_3, at))
|
2020-11-06 03:13:54 +00:00
|
|
|
})
|
2020-08-27 16:10:55 +00:00
|
|
|
.collect();
|
|
|
|
|
|
2020-09-17 16:33:42 +00:00
|
|
|
let aux_evals: Vec<_> = meta
|
|
|
|
|
.aux_queries
|
|
|
|
|
.iter()
|
2020-11-06 03:13:54 +00:00
|
|
|
.map(|&(column, at)| {
|
2020-11-09 16:45:52 +00:00
|
|
|
eval_polynomial(&aux_polys[column.index()], domain.rotate_omega(x_3, at))
|
2020-11-06 03:13:54 +00:00
|
|
|
})
|
2020-09-17 16:33:42 +00:00
|
|
|
.collect();
|
|
|
|
|
|
2020-08-27 16:25:36 +00:00
|
|
|
let fixed_evals: Vec<_> = meta
|
2020-08-27 16:10:55 +00:00
|
|
|
.fixed_queries
|
|
|
|
|
.iter()
|
2020-11-06 03:13:54 +00:00
|
|
|
.map(|&(column, at)| {
|
2020-11-09 16:45:52 +00:00
|
|
|
eval_polynomial(
|
|
|
|
|
&pk.fixed_polys[column.index()],
|
|
|
|
|
domain.rotate_omega(x_3, at),
|
|
|
|
|
)
|
2020-08-27 20:03:43 +00:00
|
|
|
})
|
2020-08-27 16:10:55 +00:00
|
|
|
.collect();
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2020-08-27 16:25:36 +00:00
|
|
|
let h_evals: Vec<_> = h_pieces
|
2020-08-22 20:15:39 +00:00
|
|
|
.iter()
|
2020-08-27 16:10:55 +00:00
|
|
|
.map(|poly| eval_polynomial(poly, x_3))
|
2020-08-22 20:15:39 +00:00
|
|
|
.collect();
|
|
|
|
|
|
2020-08-27 16:10:55 +00:00
|
|
|
// Hash each advice evaluation
|
2020-09-03 23:21:44 +00:00
|
|
|
for eval in advice_evals
|
|
|
|
|
.iter()
|
2020-09-17 16:33:42 +00:00
|
|
|
.chain(aux_evals.iter())
|
2020-09-03 23:21:44 +00:00
|
|
|
.chain(fixed_evals.iter())
|
|
|
|
|
.chain(h_evals.iter())
|
|
|
|
|
{
|
2020-10-14 23:35:06 +00:00
|
|
|
transcript.absorb_scalar(*eval);
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-25 00:49:52 +00:00
|
|
|
// Evaluate the permutations, if any, at omega^i x_3.
|
|
|
|
|
let permutations = permutations.map(|p| p.evaluate(pk, x_3, &mut transcript));
|
|
|
|
|
|
2020-10-21 21:17:23 +00:00
|
|
|
let instances =
|
|
|
|
|
iter::empty()
|
|
|
|
|
.chain(pk.vk.cs.advice_queries.iter().enumerate().map(
|
|
|
|
|
|(query_index, &(column, at))| ProverQuery {
|
|
|
|
|
point: domain.rotate_omega(x_3, at),
|
|
|
|
|
poly: &advice_polys[column.index()],
|
|
|
|
|
blind: advice_blinds[column.index()],
|
|
|
|
|
eval: advice_evals[query_index],
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
.chain(pk.vk.cs.aux_queries.iter().enumerate().map(
|
|
|
|
|
|(query_index, &(column, at))| ProverQuery {
|
|
|
|
|
point: domain.rotate_omega(x_3, at),
|
|
|
|
|
poly: &aux_polys[column.index()],
|
|
|
|
|
blind: Blind::default(),
|
|
|
|
|
eval: aux_evals[query_index],
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
.chain(pk.vk.cs.fixed_queries.iter().enumerate().map(
|
|
|
|
|
|(query_index, &(column, at))| ProverQuery {
|
|
|
|
|
point: domain.rotate_omega(x_3, at),
|
|
|
|
|
poly: &pk.fixed_polys[column.index()],
|
|
|
|
|
blind: Blind::default(),
|
|
|
|
|
eval: fixed_evals[query_index],
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
// We query the h(X) polynomial at x_3
|
|
|
|
|
.chain(
|
|
|
|
|
h_pieces
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(h_blinds.iter())
|
|
|
|
|
.zip(h_evals.iter())
|
|
|
|
|
.map(|((h_poly, h_blind), h_eval)| ProverQuery {
|
|
|
|
|
point: x_3,
|
|
|
|
|
poly: h_poly,
|
|
|
|
|
blind: *h_blind,
|
|
|
|
|
eval: *h_eval,
|
|
|
|
|
}),
|
|
|
|
|
);
|
2020-08-27 16:10:55 +00:00
|
|
|
|
2020-10-21 21:17:23 +00:00
|
|
|
let multiopening = multiopen::Proof::create(
|
|
|
|
|
params,
|
|
|
|
|
&mut transcript,
|
2020-11-25 00:49:52 +00:00
|
|
|
instances.chain(
|
|
|
|
|
permutations
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|p| p.open(pk, x_3))
|
|
|
|
|
.into_iter()
|
|
|
|
|
.flatten(),
|
|
|
|
|
),
|
2020-10-21 21:17:23 +00:00
|
|
|
)
|
|
|
|
|
.map_err(|_| Error::OpeningError)?;
|
2020-10-08 04:15:46 +00:00
|
|
|
|
|
|
|
|
Ok(Proof {
|
|
|
|
|
advice_commitments,
|
|
|
|
|
h_commitments,
|
2020-11-25 00:49:52 +00:00
|
|
|
permutations: permutations.map(|p| p.build()),
|
2020-10-08 04:15:46 +00:00
|
|
|
advice_evals,
|
|
|
|
|
fixed_evals,
|
|
|
|
|
aux_evals,
|
|
|
|
|
h_evals,
|
|
|
|
|
multiopening,
|
|
|
|
|
})
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
|
|
|
|
}
|