mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-05 20:10:32 +00:00
Cleanups for verifier of permutation argument
This commit is contained in:
parent
c44a020de7
commit
160dabe9c5
3 changed files with 90 additions and 50 deletions
|
|
@ -169,7 +169,7 @@ pub struct MetaCircuit<F> {
|
||||||
// another permutation between wires (B, C, D) which allows the same with D
|
// another permutation between wires (B, C, D) which allows the same with D
|
||||||
// instead of A.
|
// instead of A.
|
||||||
pub(crate) permutations: Vec<Vec<AdviceWire>>,
|
pub(crate) permutations: Vec<Vec<AdviceWire>>,
|
||||||
pub(crate) permutation_queries: Vec<Vec<Polynomial<F>>>,
|
pub(crate) permutation_queries: Vec<Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Default for MetaCircuit<F> {
|
impl<F: Field> Default for MetaCircuit<F> {
|
||||||
|
|
@ -203,7 +203,7 @@ impl<F: Field> MetaCircuit<F> {
|
||||||
|
|
||||||
let mut queries = vec![];
|
let mut queries = vec![];
|
||||||
for wire in wires {
|
for wire in wires {
|
||||||
queries.push(self.query_advice(*wire, 0));
|
queries.push(self.query_advice_index(*wire, 0));
|
||||||
}
|
}
|
||||||
self.permutation_queries.push(queries);
|
self.permutation_queries.push(queries);
|
||||||
|
|
||||||
|
|
@ -225,8 +225,7 @@ impl<F: Field> MetaCircuit<F> {
|
||||||
Polynomial::Fixed(index)
|
Polynomial::Fixed(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query an advice wire at a relative position
|
fn query_advice_index(&mut self, wire: AdviceWire, at: i32) -> usize {
|
||||||
pub fn query_advice(&mut self, wire: AdviceWire, at: i32) -> Polynomial<F> {
|
|
||||||
let at = Rotation(at);
|
let at = Rotation(at);
|
||||||
{
|
{
|
||||||
let len = self.rotations.len();
|
let len = self.rotations.len();
|
||||||
|
|
@ -237,7 +236,12 @@ impl<F: Field> MetaCircuit<F> {
|
||||||
let index = self.advice_queries.len();
|
let index = self.advice_queries.len();
|
||||||
self.advice_queries.push((wire, at));
|
self.advice_queries.push((wire, at));
|
||||||
|
|
||||||
Polynomial::Advice(index)
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Query an advice wire at a relative position
|
||||||
|
pub fn query_advice(&mut self, wire: AdviceWire, at: i32) -> Polynomial<F> {
|
||||||
|
Polynomial::Advice(self.query_advice_index(wire, at))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new gate
|
/// Create a new gate
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ pub struct EvaluationDomain<G: Group> {
|
||||||
ifft_divisor: G::Scalar,
|
ifft_divisor: G::Scalar,
|
||||||
extended_ifft_divisor: G::Scalar,
|
extended_ifft_divisor: G::Scalar,
|
||||||
t_evaluations: Vec<G::Scalar>,
|
t_evaluations: Vec<G::Scalar>,
|
||||||
|
barycentric_weight: G::Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group> EvaluationDomain<G> {
|
impl<G: Group> EvaluationDomain<G> {
|
||||||
|
|
@ -99,6 +100,10 @@ impl<G: Group> EvaluationDomain<G> {
|
||||||
G::Scalar::batch_invert(&mut t_evaluations);
|
G::Scalar::batch_invert(&mut t_evaluations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The barycentric weight of 1 over the evaluation domain
|
||||||
|
// 1 / \prod_{i != 0} (1 - omega^i)
|
||||||
|
let barycentric_weight = G::Scalar::from(n).invert().unwrap();
|
||||||
|
|
||||||
EvaluationDomain {
|
EvaluationDomain {
|
||||||
n,
|
n,
|
||||||
k,
|
k,
|
||||||
|
|
@ -113,6 +118,7 @@ impl<G: Group> EvaluationDomain<G> {
|
||||||
ifft_divisor,
|
ifft_divisor,
|
||||||
extended_ifft_divisor,
|
extended_ifft_divisor,
|
||||||
t_evaluations,
|
t_evaluations,
|
||||||
|
barycentric_weight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,4 +266,8 @@ impl<G: Group> EvaluationDomain<G> {
|
||||||
}
|
}
|
||||||
point
|
point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_barycentric_weight(&self) -> G::Scalar {
|
||||||
|
self.barycentric_weight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,9 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
// Sample x_1 challenge
|
// Sample x_1 challenge
|
||||||
let x_1: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
let x_1: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
|
||||||
// Check permutations
|
// Hash each permutation product commitment
|
||||||
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
|
for c in &self.permutation_product_commitments {
|
||||||
let mut omega_powers = Vec::with_capacity(params.n as usize);
|
hash_point(&mut transcript, c).expect("proof cannot contain points at infinity");
|
||||||
{
|
|
||||||
let mut cur = C::Scalar::one();
|
|
||||||
for _ in 0..params.n {
|
|
||||||
omega_powers.push(cur);
|
|
||||||
cur *= &srs.domain.get_omega();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample x_2 challenge, which keeps the gates linearly independent.
|
// Sample x_2 challenge, which keeps the gates linearly independent.
|
||||||
|
|
@ -47,7 +41,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
// Sample x_3 challenge, which is used to ensure the circuit is
|
// Sample x_3 challenge, which is used to ensure the circuit is
|
||||||
// satisfied with high probability.
|
// satisfied with high probability.
|
||||||
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
let xn = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
||||||
|
|
||||||
// Hash together all the openings provided by the prover into a new
|
// Hash together all the openings provided by the prover into a new
|
||||||
// transcript on the scalar field.
|
// transcript on the scalar field.
|
||||||
|
|
@ -58,6 +52,9 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
.iter()
|
.iter()
|
||||||
.chain(self.fixed_evals.iter())
|
.chain(self.fixed_evals.iter())
|
||||||
.chain(self.h_evals.iter())
|
.chain(self.h_evals.iter())
|
||||||
|
.chain(self.permutation_product_evals.iter())
|
||||||
|
.chain(self.permutation_product_inv_evals.iter())
|
||||||
|
.chain(self.permutation_evals.iter().flat_map(|evals| evals.iter()))
|
||||||
{
|
{
|
||||||
transcript_scalar.absorb(*eval);
|
transcript_scalar.absorb(*eval);
|
||||||
}
|
}
|
||||||
|
|
@ -82,46 +79,45 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
h_eval += &evaluation;
|
h_eval += &evaluation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate permutation polynomial at first point
|
// First element in each permutation product should be 1
|
||||||
// l_0(X) * (1 - z(X)) = 0
|
// l_0(X) * (1 - z(X)) = 0
|
||||||
for eval in self.permutation_product_evals.iter() {
|
{
|
||||||
h_eval *= &x_2;
|
// TODO: bubble this error up
|
||||||
|
let denominator = (x_3 - &C::Scalar::one()).invert().unwrap();
|
||||||
|
|
||||||
let mut l0_eval = (C::Scalar::from_u64(params.n) * &(xn * &x_3 - &C::Scalar::one()))
|
for eval in self.permutation_product_evals.iter() {
|
||||||
* &(x_3 - &C::Scalar::one()).invert().unwrap();
|
h_eval *= &x_2;
|
||||||
l0_eval *= &(C::Scalar::one() - &eval);
|
|
||||||
|
|
||||||
h_eval += &l0_eval;
|
let mut tmp = denominator; // 1 / (x_3 - 1)
|
||||||
|
tmp *= &(x_3n - &C::Scalar::one()); // (x_3^n - 1) / (x_3 - 1)
|
||||||
|
tmp *= &srs.domain.get_barycentric_weight(); // l_0(x_3)
|
||||||
|
tmp *= &(C::Scalar::one() - &eval); // l_0(X) * (1 - z(X))
|
||||||
|
|
||||||
|
h_eval += &tmp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate permutation polynomial at subsequent points
|
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
|
||||||
for (perm_idx, queries) in srs.meta.permutation_queries.iter().enumerate() {
|
for (permutation_index, queries) in srs.meta.permutation_queries.iter().enumerate() {
|
||||||
h_eval *= &x_2;
|
h_eval *= &x_2;
|
||||||
|
|
||||||
// queries is a vector of polynomials
|
let mut left = self.permutation_product_evals[permutation_index];
|
||||||
let evals: Vec<C::Scalar> = queries
|
for (advice_eval, permutation_eval) in queries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|poly| {
|
.map(|&query_index| self.advice_evals[query_index])
|
||||||
poly.evaluate(
|
.zip(self.permutation_evals[permutation_index].iter())
|
||||||
&|index| self.fixed_evals[index],
|
{
|
||||||
&|index| self.advice_evals[index],
|
left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1);
|
||||||
&|a, b| a + &b,
|
|
||||||
&|a, b| a * &b,
|
|
||||||
&|a, scalar| a * &scalar,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut left = self.permutation_product_inv_evals[perm_idx];
|
|
||||||
let mut cur_delta = x_0 * &x_3;
|
|
||||||
for eval in evals.iter() {
|
|
||||||
left *= &(*eval + &cur_delta + &x_1);
|
|
||||||
cur_delta *= &C::Scalar::DELTA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut right = self.permutation_product_evals[perm_idx];
|
let mut right = self.permutation_product_inv_evals[permutation_index];
|
||||||
for (perm_eval, eval) in self.permutation_evals[perm_idx].iter().zip(evals.iter()) {
|
let mut current_delta = x_0;
|
||||||
right *= &(*eval + &(x_0 * perm_eval) + &x_1);
|
for advice_eval in queries
|
||||||
|
.iter()
|
||||||
|
.map(|&query_index| self.advice_evals[query_index])
|
||||||
|
{
|
||||||
|
right *= &(advice_eval + ¤t_delta + &x_1);
|
||||||
|
current_delta *= &C::Scalar::DELTA;
|
||||||
}
|
}
|
||||||
|
|
||||||
h_eval += &left;
|
h_eval += &left;
|
||||||
|
|
@ -133,10 +129,10 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let mut cur = C::Scalar::one();
|
let mut cur = C::Scalar::one();
|
||||||
for eval in &self.h_evals {
|
for eval in &self.h_evals {
|
||||||
expected_h_eval += &(cur * eval);
|
expected_h_eval += &(cur * eval);
|
||||||
cur *= &xn;
|
cur *= &x_3n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if h_eval != (expected_h_eval * &(xn - &C::Scalar::one())) {
|
if h_eval != (expected_h_eval * &(x_3n - &C::Scalar::one())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,8 +178,38 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_index = (*srs.meta.rotations.get(&Rotation::default()).unwrap()).0;
|
let current_index = (*srs.meta.rotations.get(&Rotation::default()).unwrap()).0;
|
||||||
for (h_commitment, h_eval) in self.h_commitments.iter().zip(self.h_evals.iter()) {
|
for (commitment, eval) in self.h_commitments.iter().zip(self.h_evals.iter()) {
|
||||||
accumulate(current_index, *h_commitment, *h_eval);
|
accumulate(current_index, *commitment, *eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle permutation arguments, if any exist
|
||||||
|
if !srs.meta.permutations.is_empty() {
|
||||||
|
// Open permutation product commitments at x_3
|
||||||
|
for (commitment, eval) in self
|
||||||
|
.permutation_product_commitments
|
||||||
|
.iter()
|
||||||
|
.zip(self.permutation_product_evals.iter())
|
||||||
|
{
|
||||||
|
accumulate(current_index, *commitment, *eval);
|
||||||
|
}
|
||||||
|
// Open permutation commitments for each permutation argument at x_3
|
||||||
|
for (commitment, eval) in srs
|
||||||
|
.permutation_commitments
|
||||||
|
.iter()
|
||||||
|
.zip(self.permutation_evals.iter())
|
||||||
|
.flat_map(|(commitments, evals)| commitments.iter().zip(evals.iter()))
|
||||||
|
{
|
||||||
|
accumulate(current_index, *commitment, *eval);
|
||||||
|
}
|
||||||
|
let current_index = (*srs.meta.rotations.get(&Rotation(-1)).unwrap()).0;
|
||||||
|
// Open permutation product commitments at \omega^{-1} x_3
|
||||||
|
for (commitment, eval) in self
|
||||||
|
.permutation_product_commitments
|
||||||
|
.iter()
|
||||||
|
.zip(self.permutation_product_inv_evals.iter())
|
||||||
|
{
|
||||||
|
accumulate(current_index, *commitment, *eval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +236,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
// We can compute the expected f_eval at x_6 using the q_evals provided
|
// We can compute the expected f_eval at x_6 using the q_evals provided
|
||||||
// by the prover and from x_5
|
// by the prover and from x_5
|
||||||
let mut f_eval = C::Scalar::zero();
|
let mut f_eval = C::Scalar::zero();
|
||||||
for (&row, &point_index) in srs.meta.rotations.iter() {
|
for (&row, point_index) in srs.meta.rotations.iter() {
|
||||||
let mut eval = self.q_evals[point_index.0];
|
let mut eval = self.q_evals[point_index.0];
|
||||||
|
|
||||||
let point = srs.domain.rotate_omega(x_3, row);
|
let point = srs.domain.rotate_omega(x_3, row);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue