2020-11-30 18:09:03 -08:00
|
|
|
use ff::Field;
|
2021-02-22 11:02:53 -08:00
|
|
|
use group::Curve;
|
2020-11-30 18:09:03 -08:00
|
|
|
|
2020-12-22 10:11:42 -08:00
|
|
|
use super::{Argument, ProvingKey, VerifyingKey};
|
2020-11-30 18:09:03 -08:00
|
|
|
use crate::{
|
2021-02-22 11:02:53 -08:00
|
|
|
arithmetic::{CurveAffine, FieldExt},
|
2021-07-02 15:20:36 -07:00
|
|
|
plonk::{Any, Column, Error},
|
2020-11-30 18:09:03 -08:00
|
|
|
poly::{
|
|
|
|
commitment::{Blind, Params},
|
2021-07-12 11:57:09 -07:00
|
|
|
EvaluationDomain,
|
2020-11-30 18:09:03 -08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-01-21 20:31:27 -08:00
|
|
|
#[derive(Debug)]
|
2020-11-30 18:09:03 -08:00
|
|
|
pub(crate) struct Assembly {
|
2021-07-02 15:20:36 -07:00
|
|
|
columns: Vec<Column<Any>>,
|
2020-12-21 21:56:30 -08:00
|
|
|
pub(crate) mapping: Vec<Vec<(usize, usize)>>,
|
2020-12-22 10:11:42 -08:00
|
|
|
aux: Vec<Vec<(usize, usize)>>,
|
|
|
|
sizes: Vec<Vec<usize>>,
|
2020-11-30 18:09:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Assembly {
|
2020-12-21 21:56:30 -08:00
|
|
|
pub(crate) fn new(n: usize, p: &Argument) -> Self {
|
2020-11-30 18:09:03 -08:00
|
|
|
// Initialize the copy vector to keep track of copy constraints in all
|
|
|
|
// the permutation arguments.
|
2020-12-22 10:11:42 -08:00
|
|
|
let mut columns = vec![];
|
|
|
|
for i in 0..p.columns.len() {
|
|
|
|
// Computes [(i, 0), (i, 1), ..., (i, n - 1)]
|
2020-12-21 21:56:30 -08:00
|
|
|
columns.push((0..n).map(|j| (i, j)).collect());
|
2020-11-30 18:09:03 -08:00
|
|
|
}
|
|
|
|
|
2020-12-22 12:20:58 -08:00
|
|
|
// Before any equality constraints are applied, every cell in the permutation is
|
|
|
|
// in a 1-cycle; therefore mapping and aux are identical, because every cell is
|
|
|
|
// its own distinguished element.
|
2020-12-22 10:11:42 -08:00
|
|
|
Assembly {
|
2021-07-02 15:20:36 -07:00
|
|
|
columns: p.columns.clone(),
|
2020-12-22 10:11:42 -08:00
|
|
|
mapping: columns.clone(),
|
|
|
|
aux: columns,
|
2020-12-21 21:56:30 -08:00
|
|
|
sizes: vec![vec![1usize; n]; p.columns.len()],
|
2020-12-22 10:11:42 -08:00
|
|
|
}
|
2020-11-30 18:09:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn copy(
|
|
|
|
&mut self,
|
2021-07-02 15:20:36 -07:00
|
|
|
left_column: Column<Any>,
|
2020-11-30 18:09:03 -08:00
|
|
|
left_row: usize,
|
2021-07-02 15:20:36 -07:00
|
|
|
right_column: Column<Any>,
|
2020-11-30 18:09:03 -08:00
|
|
|
right_row: usize,
|
|
|
|
) -> Result<(), Error> {
|
2021-07-02 15:20:36 -07:00
|
|
|
let left_column = self
|
|
|
|
.columns
|
|
|
|
.iter()
|
|
|
|
.position(|c| c == &left_column)
|
2021-10-14 03:29:28 -07:00
|
|
|
.ok_or(Error::ColumnNotInPermutation(left_column))?;
|
2021-07-02 15:20:36 -07:00
|
|
|
let right_column = self
|
|
|
|
.columns
|
|
|
|
.iter()
|
|
|
|
.position(|c| c == &right_column)
|
2021-10-14 03:29:28 -07:00
|
|
|
.ok_or(Error::ColumnNotInPermutation(right_column))?;
|
2021-07-02 15:20:36 -07:00
|
|
|
|
|
|
|
// Check bounds
|
|
|
|
if left_row >= self.mapping[left_column].len()
|
2020-12-22 10:11:42 -08:00
|
|
|
|| right_row >= self.mapping[right_column].len()
|
2020-11-30 18:09:03 -08:00
|
|
|
{
|
|
|
|
return Err(Error::BoundsFailure);
|
|
|
|
}
|
|
|
|
|
2020-12-22 12:20:58 -08:00
|
|
|
// See book/src/design/permutation.md for a description of this algorithm.
|
|
|
|
|
2020-12-22 10:11:42 -08:00
|
|
|
let mut left_cycle = self.aux[left_column][left_row];
|
|
|
|
let mut right_cycle = self.aux[right_column][right_row];
|
2020-11-30 18:09:03 -08:00
|
|
|
|
2020-12-22 12:20:58 -08:00
|
|
|
// If left and right are in the same cycle, do nothing.
|
2020-11-30 18:09:03 -08:00
|
|
|
if left_cycle == right_cycle {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2020-12-22 10:11:42 -08:00
|
|
|
if self.sizes[left_cycle.0][left_cycle.1] < self.sizes[right_cycle.0][right_cycle.1] {
|
2020-11-30 18:09:03 -08:00
|
|
|
std::mem::swap(&mut left_cycle, &mut right_cycle);
|
|
|
|
}
|
|
|
|
|
2020-12-22 12:20:58 -08:00
|
|
|
// Merge the right cycle into the left one.
|
2020-12-22 10:11:42 -08:00
|
|
|
self.sizes[left_cycle.0][left_cycle.1] += self.sizes[right_cycle.0][right_cycle.1];
|
2020-11-30 18:09:03 -08:00
|
|
|
let mut i = right_cycle;
|
|
|
|
loop {
|
2020-12-22 10:11:42 -08:00
|
|
|
self.aux[i.0][i.1] = left_cycle;
|
|
|
|
i = self.mapping[i.0][i.1];
|
2020-11-30 18:09:03 -08:00
|
|
|
if i == right_cycle {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-22 10:11:42 -08:00
|
|
|
let tmp = self.mapping[left_column][left_row];
|
|
|
|
self.mapping[left_column][left_row] = self.mapping[right_column][right_row];
|
|
|
|
self.mapping[right_column][right_row] = tmp;
|
2020-11-30 18:09:03 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
pub(crate) fn build_vk<C: CurveAffine>(
|
|
|
|
self,
|
2020-11-30 18:09:03 -08:00
|
|
|
params: &Params<C>,
|
|
|
|
domain: &EvaluationDomain<C::Scalar>,
|
2021-07-02 15:20:36 -07:00
|
|
|
p: &Argument,
|
|
|
|
) -> VerifyingKey<C> {
|
2020-11-30 18:09:03 -08:00
|
|
|
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
|
|
|
|
let mut omega_powers = Vec::with_capacity(params.n as usize);
|
|
|
|
{
|
|
|
|
let mut cur = C::Scalar::one();
|
|
|
|
for _ in 0..params.n {
|
|
|
|
omega_powers.push(cur);
|
|
|
|
cur *= &domain.get_omega();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
|
2021-07-02 15:20:36 -07:00
|
|
|
let mut deltaomega = Vec::with_capacity(p.columns.len());
|
2020-11-30 18:09:03 -08:00
|
|
|
{
|
|
|
|
let mut cur = C::Scalar::one();
|
2021-07-02 15:20:36 -07:00
|
|
|
for _ in 0..p.columns.len() {
|
2020-11-30 18:09:03 -08:00
|
|
|
let mut omega_powers = omega_powers.clone();
|
|
|
|
for o in &mut omega_powers {
|
|
|
|
*o *= &cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
deltaomega.push(omega_powers);
|
|
|
|
|
|
|
|
cur *= &C::Scalar::DELTA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-21 20:31:27 -08:00
|
|
|
// Pre-compute commitments for the URS.
|
2020-12-22 10:11:42 -08:00
|
|
|
let mut commitments = vec![];
|
|
|
|
for i in 0..p.columns.len() {
|
|
|
|
// Computes the permutation polynomial based on the permutation
|
|
|
|
// description in the assembly.
|
|
|
|
let mut permutation_poly = domain.empty_lagrange();
|
|
|
|
for (j, p) in permutation_poly.iter_mut().enumerate() {
|
|
|
|
let (permuted_i, permuted_j) = self.mapping[i][j];
|
2021-07-02 15:20:36 -07:00
|
|
|
*p = deltaomega[permuted_i][permuted_j];
|
2020-11-30 18:09:03 -08:00
|
|
|
}
|
2020-12-22 10:11:42 -08:00
|
|
|
|
|
|
|
// Compute commitment to permutation polynomial
|
|
|
|
commitments.push(
|
|
|
|
params
|
|
|
|
.commit_lagrange(&permutation_poly, Blind::default())
|
|
|
|
.to_affine(),
|
|
|
|
);
|
2021-01-13 09:23:01 -08:00
|
|
|
}
|
|
|
|
VerifyingKey { commitments }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn build_pk<C: CurveAffine>(
|
|
|
|
self,
|
2021-07-02 15:20:36 -07:00
|
|
|
params: &Params<C>,
|
2021-01-13 09:23:01 -08:00
|
|
|
domain: &EvaluationDomain<C::Scalar>,
|
|
|
|
p: &Argument,
|
|
|
|
) -> ProvingKey<C> {
|
2021-07-02 15:20:36 -07:00
|
|
|
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
|
|
|
|
let mut omega_powers = Vec::with_capacity(params.n as usize);
|
|
|
|
{
|
|
|
|
let mut cur = C::Scalar::one();
|
|
|
|
for _ in 0..params.n {
|
|
|
|
omega_powers.push(cur);
|
|
|
|
cur *= &domain.get_omega();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
|
|
|
|
let mut deltaomega = Vec::with_capacity(p.columns.len());
|
|
|
|
{
|
|
|
|
let mut cur = C::Scalar::one();
|
|
|
|
for _ in 0..p.columns.len() {
|
|
|
|
let mut omega_powers = omega_powers.clone();
|
|
|
|
for o in &mut omega_powers {
|
|
|
|
*o *= &cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
deltaomega.push(omega_powers);
|
|
|
|
|
|
|
|
cur *= &C::Scalar::DELTA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 09:23:01 -08:00
|
|
|
// Compute permutation polynomials, convert to coset form.
|
|
|
|
let mut permutations = vec![];
|
|
|
|
let mut polys = vec![];
|
|
|
|
let mut cosets = vec![];
|
|
|
|
for i in 0..p.columns.len() {
|
|
|
|
// Computes the permutation polynomial based on the permutation
|
|
|
|
// description in the assembly.
|
|
|
|
let mut permutation_poly = domain.empty_lagrange();
|
|
|
|
for (j, p) in permutation_poly.iter_mut().enumerate() {
|
|
|
|
let (permuted_i, permuted_j) = self.mapping[i][j];
|
2021-07-02 15:20:36 -07:00
|
|
|
*p = deltaomega[permuted_i][permuted_j];
|
2021-01-13 09:23:01 -08:00
|
|
|
}
|
|
|
|
|
2020-12-22 10:11:42 -08:00
|
|
|
// Store permutation polynomial and precompute its coset evaluation
|
|
|
|
permutations.push(permutation_poly.clone());
|
|
|
|
let poly = domain.lagrange_to_coeff(permutation_poly);
|
|
|
|
polys.push(poly.clone());
|
2021-07-12 11:57:09 -07:00
|
|
|
cosets.push(domain.coeff_to_extended(poly));
|
2020-12-22 10:11:42 -08:00
|
|
|
}
|
2021-01-13 09:23:01 -08:00
|
|
|
ProvingKey {
|
|
|
|
permutations,
|
|
|
|
polys,
|
|
|
|
cosets,
|
|
|
|
}
|
2020-11-30 18:09:03 -08:00
|
|
|
}
|
|
|
|
}
|