Replace `Error::BoundsFailure` uses with `Error::NotEnoughRowsAvailable`

The remaining uses of `Error::BoundsFailure` that are exposed to the
user, are for invalid column indices.
This commit is contained in:
Jack Grigg 2021-11-15 22:45:26 +00:00
parent d055acda31
commit eb88a2ebef
5 changed files with 57 additions and 16 deletions

View File

@ -324,9 +324,19 @@ impl<F: Group + Field> Mul<F> for Value<F> {
/// row: 0
/// }])
/// );
///
/// // If we provide a too-small K, we get an error.
/// assert!(matches!(
/// MockProver::<Fp>::run(2, &circuit, vec![]).unwrap_err(),
/// Error::NotEnoughRowsAvailable {
/// current_k,
/// minimum_k,
/// } if current_k == 2 && minimum_k == 3,
/// ));
/// ```
#[derive(Debug)]
pub struct MockProver<F: Group + Field> {
k: u32,
n: u32,
cs: ConstraintSystem<F>,
@ -376,7 +386,7 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
// Track that this selector was enabled. We require that all selectors are enabled
@ -396,7 +406,7 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
fn query_instance(&self, column: Column<Instance>, row: usize) -> Result<Option<F>, Error> {
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
self.instance
@ -420,7 +430,7 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
if let Some(region) = self.current_region.as_mut() {
@ -451,7 +461,7 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
if let Some(region) = self.current_region.as_mut() {
@ -475,8 +485,11 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
right_column: Column<Any>,
right_row: usize,
) -> Result<(), crate::plonk::Error> {
if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
return Err(Error::BoundsFailure);
if !self.usable_rows.contains(&left_row) {
return Err(Error::not_enough_rows_available(self.k, left_row + 1));
}
if !self.usable_rows.contains(&right_row) {
return Err(Error::not_enough_rows_available(self.k, right_row + 1));
}
self.permutation
@ -490,7 +503,7 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
_: Option<Assigned<F>>,
) -> Result<(), Error> {
if !self.usable_rows.contains(&from_row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, from_row + 1));
}
Ok(())
@ -564,6 +577,7 @@ impl<F: FieldExt> MockProver<F> {
let constants = cs.constants.clone();
let mut prover = MockProver {
k,
n: n as u32,
cs,
regions: vec![],

View File

@ -1,3 +1,4 @@
use std::cmp;
use std::error;
use std::fmt;
use std::io;
@ -45,9 +46,16 @@ impl From<io::Error> for Error {
impl Error {
/// Constructs an `Error::NotEnoughRowsAvailable`, computing the required `k` value.
pub(crate) fn not_enough_rows_available(current_k: u32, required_rows: usize) -> Self {
// To avoid needing to pass around the required number of blinding factors, we
// assume here that k always needs to increment by at least 1.
let minimum_k = cmp::max(
current_k + 1,
(required_rows.next_power_of_two() as f64).log2() as u32,
);
Error::NotEnoughRowsAvailable {
current_k,
minimum_k: (required_rows.next_power_of_two() as f64).log2() as u32,
minimum_k,
}
}
}

View File

@ -42,6 +42,7 @@ where
/// Assembly to be used in circuit synthesis.
#[derive(Debug)]
struct Assembly<F: Field> {
k: u32,
fixed: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
permutation: permutation::keygen::Assembly,
selectors: Vec<Vec<bool>>,
@ -69,7 +70,7 @@ impl<F: Field> Assignment<F> for Assembly<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
self.selectors[selector.0][row] = true;
@ -79,7 +80,7 @@ impl<F: Field> Assignment<F> for Assembly<F> {
fn query_instance(&self, _: Column<Instance>, row: usize) -> Result<Option<F>, Error> {
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
// There is no instance in this context.
@ -117,7 +118,7 @@ impl<F: Field> Assignment<F> for Assembly<F> {
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
*self
@ -136,8 +137,11 @@ impl<F: Field> Assignment<F> for Assembly<F> {
right_column: Column<Any>,
right_row: usize,
) -> Result<(), Error> {
if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
return Err(Error::BoundsFailure);
if !self.usable_rows.contains(&left_row) {
return Err(Error::not_enough_rows_available(self.k, left_row + 1));
}
if !self.usable_rows.contains(&right_row) {
return Err(Error::not_enough_rows_available(self.k, right_row + 1));
}
self.permutation
@ -151,7 +155,7 @@ impl<F: Field> Assignment<F> for Assembly<F> {
to: Option<Assigned<F>>,
) -> Result<(), Error> {
if !self.usable_rows.contains(&from_row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, from_row + 1));
}
let col = self
@ -198,6 +202,7 @@ where
}
let mut assembly: Assembly<C::Scalar> = Assembly {
k: params.k,
fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
permutation: permutation::keygen::Assembly::new(params.n as usize, &cs.permutation),
selectors: vec![vec![false; params.n as usize]; cs.num_selectors],
@ -261,6 +266,7 @@ where
}
let mut assembly: Assembly<C::Scalar> = Assembly {
k: params.k,
fixed: vec![vk.domain.empty_lagrange_assigned(); cs.num_fixed_columns],
permutation: permutation::keygen::Assembly::new(params.n as usize, &cs.permutation),
selectors: vec![vec![false; params.n as usize]; cs.num_selectors],

View File

@ -128,6 +128,7 @@ pub fn create_proof<
.zip(instances.iter())
.map(|(circuit, instances)| -> Result<AdviceSingle<C>, Error> {
struct WitnessCollection<'a, F: Field> {
k: u32,
pub advice: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
instances: &'a [&'a [F]],
usable_rows: RangeTo<usize>,
@ -168,7 +169,7 @@ pub fn create_proof<
row: usize,
) -> Result<Option<F>, Error> {
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
self.instances
@ -192,7 +193,7 @@ pub fn create_proof<
AR: Into<String>,
{
if !self.usable_rows.contains(&row) {
return Err(Error::BoundsFailure);
return Err(Error::not_enough_rows_available(self.k, row + 1));
}
*self
@ -259,6 +260,7 @@ pub fn create_proof<
let unusable_rows_start = params.n as usize - (meta.blinding_factors() + 1);
let mut witness = WitnessCollection {
k: params.k,
advice: vec![domain.empty_lagrange_assigned(); meta.num_advice_columns],
instances,
// The prover will not be allowed to assign values to advice

View File

@ -405,6 +405,17 @@ fn plonk_api() {
}) if current_k == 1 && minimum_k == 3
);
// Check that we get an error if we try to initialize the proving key with a value of
// k that is too small for the number of rows the circuit uses.
let slightly_too_small_params: Params<EqAffine> = Params::new(K - 1);
assert_matches!(
keygen_vk(&slightly_too_small_params, &empty_circuit),
Err(Error::NotEnoughRowsAvailable {
current_k,
minimum_k,
}) if current_k == K - 1 && minimum_k == K
);
// Initialize the proving key
let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");