2021-07-02 15:33:22 -07:00
|
|
|
#![allow(clippy::int_plus_one)]
|
|
|
|
|
2021-07-26 17:34:51 -07:00
|
|
|
use std::ops::Range;
|
2021-07-09 11:38:38 -07:00
|
|
|
|
2022-11-29 21:05:37 -08:00
|
|
|
use ff::{Field, FromUniformBytes};
|
2021-02-22 11:02:53 -08:00
|
|
|
use group::Curve;
|
2020-11-12 16:08:08 -08:00
|
|
|
|
2020-09-29 07:25:04 -07:00
|
|
|
use super::{
|
2021-06-21 11:10:59 -07:00
|
|
|
circuit::{
|
2021-07-08 13:44:01 -07:00
|
|
|
Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed, FloorPlanner, Instance,
|
|
|
|
Selector,
|
2021-06-21 11:10:59 -07:00
|
|
|
},
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation, Assigned, Error, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey,
|
2020-09-29 07:25:04 -07:00
|
|
|
};
|
2022-06-07 16:15:35 -07:00
|
|
|
use crate::{
|
|
|
|
arithmetic::CurveAffine,
|
|
|
|
circuit::Value,
|
|
|
|
poly::{
|
|
|
|
batch_invert_assigned,
|
|
|
|
commitment::{Blind, Params},
|
|
|
|
EvaluationDomain,
|
|
|
|
},
|
2020-09-29 07:25:04 -07:00
|
|
|
};
|
|
|
|
|
2021-01-12 07:01:50 -08:00
|
|
|
pub(crate) fn create_domain<C, ConcreteCircuit>(
|
|
|
|
params: &Params<C>,
|
|
|
|
) -> (
|
|
|
|
EvaluationDomain<C::Scalar>,
|
|
|
|
ConstraintSystem<C::Scalar>,
|
|
|
|
ConcreteCircuit::Config,
|
|
|
|
)
|
|
|
|
where
|
|
|
|
C: CurveAffine,
|
|
|
|
ConcreteCircuit: Circuit<C::Scalar>,
|
|
|
|
{
|
|
|
|
let mut cs = ConstraintSystem::default();
|
|
|
|
let config = ConcreteCircuit::configure(&mut cs);
|
|
|
|
|
2021-02-24 09:19:46 -08:00
|
|
|
let degree = cs.degree();
|
2021-01-12 07:01:50 -08:00
|
|
|
|
|
|
|
let domain = EvaluationDomain::new(degree as u32, params.k);
|
|
|
|
|
|
|
|
(domain, cs, config)
|
|
|
|
}
|
|
|
|
|
2021-01-13 09:23:01 -08:00
|
|
|
/// Assembly to be used in circuit synthesis.
|
2021-01-21 20:31:27 -08:00
|
|
|
#[derive(Debug)]
|
2021-01-22 08:57:38 -08:00
|
|
|
struct Assembly<F: Field> {
|
2021-11-15 14:45:26 -08:00
|
|
|
k: u32,
|
2021-06-11 09:34:25 -07:00
|
|
|
fixed: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation: permutation::keygen::Assembly,
|
2021-07-21 11:55:19 -07:00
|
|
|
selectors: Vec<Vec<bool>>,
|
2021-07-09 11:38:38 -07:00
|
|
|
// A range of available rows for assignment and copies.
|
2021-07-26 17:34:51 -07:00
|
|
|
usable_rows: Range<usize>,
|
2021-01-13 09:23:01 -08:00
|
|
|
_marker: std::marker::PhantomData<F>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> Assignment<F> for Assembly<F> {
|
2021-01-22 08:43:36 -08:00
|
|
|
fn enter_region<NR, N>(&mut self, _: N)
|
|
|
|
where
|
|
|
|
NR: Into<String>,
|
|
|
|
N: FnOnce() -> NR,
|
|
|
|
{
|
|
|
|
// Do nothing; we don't care about regions in this context.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn exit_region(&mut self) {
|
|
|
|
// Do nothing; we don't care about regions in this context.
|
|
|
|
}
|
|
|
|
|
2021-07-21 11:55:19 -07:00
|
|
|
fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
|
2021-05-27 04:43:32 -07:00
|
|
|
where
|
|
|
|
A: FnOnce() -> AR,
|
|
|
|
AR: Into<String>,
|
|
|
|
{
|
2021-07-09 11:38:38 -07:00
|
|
|
if !self.usable_rows.contains(&row) {
|
2021-11-16 23:54:26 -08:00
|
|
|
return Err(Error::not_enough_rows_available(self.k));
|
2021-07-02 15:20:36 -07:00
|
|
|
}
|
2021-07-21 11:55:19 -07:00
|
|
|
|
|
|
|
self.selectors[selector.0][row] = true;
|
|
|
|
|
|
|
|
Ok(())
|
2021-05-27 04:43:32 -07:00
|
|
|
}
|
|
|
|
|
2022-06-07 16:15:35 -07:00
|
|
|
fn query_instance(&self, _: Column<Instance>, row: usize) -> Result<Value<F>, Error> {
|
2021-07-10 07:25:00 -07:00
|
|
|
if !self.usable_rows.contains(&row) {
|
2021-11-16 23:54:26 -08:00
|
|
|
return Err(Error::not_enough_rows_available(self.k));
|
2021-07-10 07:25:00 -07:00
|
|
|
}
|
|
|
|
|
2021-07-08 13:44:01 -07:00
|
|
|
// There is no instance in this context.
|
2022-06-07 16:15:35 -07:00
|
|
|
Ok(Value::unknown())
|
2021-07-08 13:44:01 -07:00
|
|
|
}
|
|
|
|
|
2021-06-11 08:39:34 -07:00
|
|
|
fn assign_advice<V, VR, A, AR>(
|
2021-01-13 09:23:01 -08:00
|
|
|
&mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
_: A,
|
2021-01-13 09:23:01 -08:00
|
|
|
_: Column<Advice>,
|
|
|
|
_: usize,
|
2021-01-22 08:57:38 -08:00
|
|
|
_: V,
|
|
|
|
) -> Result<(), Error>
|
|
|
|
where
|
2022-06-07 16:15:35 -07:00
|
|
|
V: FnOnce() -> Value<VR>,
|
2021-06-11 08:39:34 -07:00
|
|
|
VR: Into<Assigned<F>>,
|
2021-01-22 08:57:38 -08:00
|
|
|
A: FnOnce() -> AR,
|
|
|
|
AR: Into<String>,
|
|
|
|
{
|
2021-01-13 09:23:01 -08:00
|
|
|
// We only care about fixed columns here
|
|
|
|
Ok(())
|
2020-09-29 07:25:04 -07:00
|
|
|
}
|
|
|
|
|
2021-06-11 08:39:34 -07:00
|
|
|
fn assign_fixed<V, VR, A, AR>(
|
2021-01-13 09:23:01 -08:00
|
|
|
&mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
_: A,
|
2021-01-13 09:23:01 -08:00
|
|
|
column: Column<Fixed>,
|
|
|
|
row: usize,
|
2021-01-22 08:57:38 -08:00
|
|
|
to: V,
|
|
|
|
) -> Result<(), Error>
|
|
|
|
where
|
2022-06-07 16:15:35 -07:00
|
|
|
V: FnOnce() -> Value<VR>,
|
2021-06-11 08:39:34 -07:00
|
|
|
VR: Into<Assigned<F>>,
|
2021-01-22 08:57:38 -08:00
|
|
|
A: FnOnce() -> AR,
|
|
|
|
AR: Into<String>,
|
|
|
|
{
|
2021-07-09 11:38:38 -07:00
|
|
|
if !self.usable_rows.contains(&row) {
|
2021-11-16 23:54:26 -08:00
|
|
|
return Err(Error::not_enough_rows_available(self.k));
|
2021-07-02 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2021-01-13 09:23:01 -08:00
|
|
|
*self
|
|
|
|
.fixed
|
|
|
|
.get_mut(column.index())
|
|
|
|
.and_then(|v| v.get_mut(row))
|
2022-06-07 16:15:35 -07:00
|
|
|
.ok_or(Error::BoundsFailure)? = to().into_field().assign()?;
|
2021-01-13 09:23:01 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-09-29 07:25:04 -07:00
|
|
|
|
2021-01-13 09:23:01 -08:00
|
|
|
fn copy(
|
|
|
|
&mut self,
|
2021-02-18 23:07:08 -08:00
|
|
|
left_column: Column<Any>,
|
2021-01-13 09:23:01 -08:00
|
|
|
left_row: usize,
|
2021-02-18 23:07:08 -08:00
|
|
|
right_column: Column<Any>,
|
2021-01-13 09:23:01 -08:00
|
|
|
right_row: usize,
|
|
|
|
) -> Result<(), Error> {
|
2021-11-16 23:54:26 -08:00
|
|
|
if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
|
|
|
|
return Err(Error::not_enough_rows_available(self.k));
|
2020-09-29 07:25:04 -07:00
|
|
|
}
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
self.permutation
|
|
|
|
.copy(left_column, left_row, right_column, right_row)
|
2020-09-29 07:25:04 -07:00
|
|
|
}
|
2021-01-22 10:36:42 -08:00
|
|
|
|
2021-07-26 17:34:51 -07:00
|
|
|
fn fill_from_row(
|
|
|
|
&mut self,
|
|
|
|
column: Column<Fixed>,
|
|
|
|
from_row: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
to: Value<Assigned<F>>,
|
2021-07-26 17:34:51 -07:00
|
|
|
) -> Result<(), Error> {
|
|
|
|
if !self.usable_rows.contains(&from_row) {
|
2021-11-16 23:54:26 -08:00
|
|
|
return Err(Error::not_enough_rows_available(self.k));
|
2021-07-26 17:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let col = self
|
|
|
|
.fixed
|
|
|
|
.get_mut(column.index())
|
|
|
|
.ok_or(Error::BoundsFailure)?;
|
|
|
|
|
2022-06-07 16:15:35 -07:00
|
|
|
let filler = to.assign()?;
|
2021-07-26 17:34:51 -07:00
|
|
|
for row in self.usable_rows.clone().skip(from_row) {
|
2022-06-07 16:15:35 -07:00
|
|
|
col[row] = filler;
|
2021-07-26 17:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-22 10:36:42 -08:00
|
|
|
fn push_namespace<NR, N>(&mut self, _: N)
|
|
|
|
where
|
|
|
|
NR: Into<String>,
|
|
|
|
N: FnOnce() -> NR,
|
|
|
|
{
|
|
|
|
// Do nothing; we don't care about namespaces in this context.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_namespace(&mut self, _: Option<String>) {
|
|
|
|
// Do nothing; we don't care about namespaces in this context.
|
|
|
|
}
|
2021-01-13 09:23:01 -08:00
|
|
|
}
|
2020-09-29 07:25:04 -07:00
|
|
|
|
2021-01-13 09:23:01 -08:00
|
|
|
/// Generate a `VerifyingKey` from an instance of `Circuit`.
|
|
|
|
pub fn keygen_vk<C, ConcreteCircuit>(
|
|
|
|
params: &Params<C>,
|
|
|
|
circuit: &ConcreteCircuit,
|
|
|
|
) -> Result<VerifyingKey<C>, Error>
|
|
|
|
where
|
|
|
|
C: CurveAffine,
|
2022-11-29 21:05:37 -08:00
|
|
|
C::Scalar: FromUniformBytes<64>,
|
2021-01-13 09:23:01 -08:00
|
|
|
ConcreteCircuit: Circuit<C::Scalar>,
|
|
|
|
{
|
2021-01-12 07:01:50 -08:00
|
|
|
let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(params);
|
2020-09-29 07:25:04 -07:00
|
|
|
|
2021-07-09 08:14:52 -07:00
|
|
|
if (params.n as usize) < cs.minimum_rows() {
|
2021-11-16 23:54:26 -08:00
|
|
|
return Err(Error::not_enough_rows_available(params.k));
|
2021-07-09 08:14:52 -07:00
|
|
|
}
|
|
|
|
|
2020-09-29 07:25:04 -07:00
|
|
|
let mut assembly: Assembly<C::Scalar> = Assembly {
|
2021-11-15 14:45:26 -08:00
|
|
|
k: params.k,
|
2021-06-11 09:34:25 -07:00
|
|
|
fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation: permutation::keygen::Assembly::new(params.n as usize, &cs.permutation),
|
2021-07-21 11:55:19 -07:00
|
|
|
selectors: vec![vec![false; params.n as usize]; cs.num_selectors],
|
2021-07-26 17:34:51 -07:00
|
|
|
usable_rows: 0..params.n as usize - (cs.blinding_factors() + 1),
|
2020-09-29 07:25:04 -07:00
|
|
|
_marker: std::marker::PhantomData,
|
|
|
|
};
|
|
|
|
|
2021-01-21 20:31:27 -08:00
|
|
|
// Synthesize the circuit to obtain URS
|
2021-07-20 08:01:38 -07:00
|
|
|
ConcreteCircuit::FloorPlanner::synthesize(
|
|
|
|
&mut assembly,
|
|
|
|
circuit,
|
|
|
|
config,
|
|
|
|
cs.constants.clone(),
|
|
|
|
)?;
|
2020-09-29 07:25:04 -07:00
|
|
|
|
2021-07-21 11:55:19 -07:00
|
|
|
let mut fixed = batch_invert_assigned(assembly.fixed);
|
|
|
|
let (cs, selector_polys) = cs.compress_selectors(assembly.selectors);
|
|
|
|
fixed.extend(
|
|
|
|
selector_polys
|
|
|
|
.into_iter()
|
|
|
|
.map(|poly| domain.lagrange_from_vec(poly)),
|
|
|
|
);
|
2021-06-11 09:34:25 -07:00
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
let permutation_vk = assembly
|
|
|
|
.permutation
|
|
|
|
.build_vk(params, &domain, &cs.permutation);
|
2020-09-29 07:25:04 -07:00
|
|
|
|
2021-06-11 09:34:25 -07:00
|
|
|
let fixed_commitments = fixed
|
2020-09-29 07:25:04 -07:00
|
|
|
.iter()
|
|
|
|
.map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
|
|
|
|
.collect();
|
|
|
|
|
2022-06-22 12:25:32 -07:00
|
|
|
Ok(VerifyingKey::from_parts(
|
2021-01-13 09:23:01 -08:00
|
|
|
domain,
|
|
|
|
fixed_commitments,
|
2022-06-22 12:25:32 -07:00
|
|
|
permutation_vk,
|
2021-01-13 09:23:01 -08:00
|
|
|
cs,
|
2022-06-22 12:25:32 -07:00
|
|
|
))
|
2021-01-13 09:23:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`.
|
|
|
|
pub fn keygen_pk<C, ConcreteCircuit>(
|
|
|
|
params: &Params<C>,
|
|
|
|
vk: VerifyingKey<C>,
|
|
|
|
circuit: &ConcreteCircuit,
|
|
|
|
) -> Result<ProvingKey<C>, Error>
|
|
|
|
where
|
|
|
|
C: CurveAffine,
|
|
|
|
ConcreteCircuit: Circuit<C::Scalar>,
|
|
|
|
{
|
|
|
|
let mut cs = ConstraintSystem::default();
|
|
|
|
let config = ConcreteCircuit::configure(&mut cs);
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
let cs = cs;
|
2021-07-09 08:14:52 -07:00
|
|
|
|
|
|
|
if (params.n as usize) < cs.minimum_rows() {
|
2021-11-16 23:54:26 -08:00
|
|
|
return Err(Error::not_enough_rows_available(params.k));
|
2021-07-09 08:14:52 -07:00
|
|
|
}
|
2021-07-02 15:20:36 -07:00
|
|
|
|
2021-01-13 09:23:01 -08:00
|
|
|
let mut assembly: Assembly<C::Scalar> = Assembly {
|
2021-11-15 14:45:26 -08:00
|
|
|
k: params.k,
|
2021-07-21 12:34:56 -07:00
|
|
|
fixed: vec![vk.domain.empty_lagrange_assigned(); cs.num_fixed_columns],
|
|
|
|
permutation: permutation::keygen::Assembly::new(params.n as usize, &cs.permutation),
|
2021-07-21 11:55:19 -07:00
|
|
|
selectors: vec![vec![false; params.n as usize]; cs.num_selectors],
|
2021-07-26 17:34:51 -07:00
|
|
|
usable_rows: 0..params.n as usize - (cs.blinding_factors() + 1),
|
2021-01-13 09:23:01 -08:00
|
|
|
_marker: std::marker::PhantomData,
|
|
|
|
};
|
|
|
|
|
2021-01-21 20:31:27 -08:00
|
|
|
// Synthesize the circuit to obtain URS
|
2021-07-20 08:01:38 -07:00
|
|
|
ConcreteCircuit::FloorPlanner::synthesize(
|
|
|
|
&mut assembly,
|
|
|
|
circuit,
|
|
|
|
config,
|
|
|
|
cs.constants.clone(),
|
|
|
|
)?;
|
2021-01-13 09:23:01 -08:00
|
|
|
|
2021-07-21 11:55:19 -07:00
|
|
|
let mut fixed = batch_invert_assigned(assembly.fixed);
|
|
|
|
let (cs, selector_polys) = cs.compress_selectors(assembly.selectors);
|
|
|
|
fixed.extend(
|
|
|
|
selector_polys
|
|
|
|
.into_iter()
|
|
|
|
.map(|poly| vk.domain.lagrange_from_vec(poly)),
|
|
|
|
);
|
2021-06-11 09:34:25 -07:00
|
|
|
|
|
|
|
let fixed_polys: Vec<_> = fixed
|
2020-11-30 22:35:56 -08:00
|
|
|
.iter()
|
2021-01-13 09:23:01 -08:00
|
|
|
.map(|poly| vk.domain.lagrange_to_coeff(poly.clone()))
|
2020-09-29 07:25:04 -07:00
|
|
|
.collect();
|
|
|
|
|
2021-07-12 11:53:12 -07:00
|
|
|
let fixed_cosets = fixed_polys
|
2020-09-29 07:25:04 -07:00
|
|
|
.iter()
|
2021-07-12 11:57:09 -07:00
|
|
|
.map(|poly| vk.domain.coeff_to_extended(poly.clone()))
|
2020-09-29 07:25:04 -07:00
|
|
|
.collect();
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
let permutation_pk = assembly
|
|
|
|
.permutation
|
2021-07-21 12:34:56 -07:00
|
|
|
.build_pk(params, &vk.domain, &cs.permutation);
|
2021-01-13 09:23:01 -08:00
|
|
|
|
2020-09-29 07:25:04 -07:00
|
|
|
// Compute l_0(X)
|
|
|
|
// TODO: this can be done more efficiently
|
2021-01-13 09:23:01 -08:00
|
|
|
let mut l0 = vk.domain.empty_lagrange();
|
2022-11-29 21:05:37 -08:00
|
|
|
l0[0] = C::Scalar::ONE;
|
2021-01-13 09:23:01 -08:00
|
|
|
let l0 = vk.domain.lagrange_to_coeff(l0);
|
2021-07-12 11:57:09 -07:00
|
|
|
let l0 = vk.domain.coeff_to_extended(l0);
|
2020-09-29 07:25:04 -07:00
|
|
|
|
2021-07-09 08:18:45 -07:00
|
|
|
// Compute l_blind(X) which evaluates to 1 for each blinding factor row
|
2021-07-02 15:20:36 -07:00
|
|
|
// and 0 otherwise over the domain.
|
2021-07-09 08:18:45 -07:00
|
|
|
let mut l_blind = vk.domain.empty_lagrange();
|
|
|
|
for evaluation in l_blind[..].iter_mut().rev().take(cs.blinding_factors()) {
|
2022-11-29 21:05:37 -08:00
|
|
|
*evaluation = C::Scalar::ONE;
|
2021-07-02 15:20:36 -07:00
|
|
|
}
|
2021-07-09 08:18:45 -07:00
|
|
|
let l_blind = vk.domain.lagrange_to_coeff(l_blind);
|
2021-07-12 11:57:09 -07:00
|
|
|
let l_blind = vk.domain.coeff_to_extended(l_blind);
|
2021-07-02 15:20:36 -07:00
|
|
|
|
|
|
|
// Compute l_last(X) which evaluates to 1 on the first inactive row (just
|
|
|
|
// before the blinding factors) and 0 otherwise over the domain
|
|
|
|
let mut l_last = vk.domain.empty_lagrange();
|
2022-11-29 21:05:37 -08:00
|
|
|
l_last[params.n as usize - cs.blinding_factors() - 1] = C::Scalar::ONE;
|
2021-07-02 15:20:36 -07:00
|
|
|
let l_last = vk.domain.lagrange_to_coeff(l_last);
|
2021-07-12 11:57:09 -07:00
|
|
|
let l_last = vk.domain.coeff_to_extended(l_last);
|
2021-07-02 15:20:36 -07:00
|
|
|
|
2020-09-29 07:25:04 -07:00
|
|
|
Ok(ProvingKey {
|
2021-01-13 09:23:01 -08:00
|
|
|
vk,
|
2020-09-29 07:25:04 -07:00
|
|
|
l0,
|
2021-07-09 08:18:45 -07:00
|
|
|
l_blind,
|
2021-07-02 15:20:36 -07:00
|
|
|
l_last,
|
2021-06-11 09:34:25 -07:00
|
|
|
fixed_values: fixed,
|
2020-09-29 07:25:04 -07:00
|
|
|
fixed_polys,
|
|
|
|
fixed_cosets,
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation: permutation_pk,
|
2020-09-29 07:25:04 -07:00
|
|
|
})
|
|
|
|
}
|