Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Doc, unit test, minors #289

Merged
merged 8 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion halo2_backend/src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::poly::{
Polynomial,
};
use crate::transcript::{ChallengeScalar, EncodedChallenge, Transcript};
use evaluation::Evaluator;
pub(crate) use evaluation::Evaluator;
use halo2_common::plonk::{Circuit, ConstraintSystem, PinnedConstraintSystem};
use halo2_common::SerdeFormat;

Expand All @@ -32,14 +32,19 @@ pub mod verifier;
/// particular circuit.
#[derive(Clone, Debug)]
pub struct VerifyingKey<C: CurveAffine> {
/// Evaluation domain
domain: EvaluationDomain<C::Scalar>,
/// Commitments to fixed columns
fixed_commitments: Vec<C>,
/// Permutation verifying key
permutation: permutation::VerifyingKey<C>,
/// Constraint system
cs: ConstraintSystem<C::Scalar>,
/// Cached maximum degree of `cs` (which doesn't change after construction).
cs_degree: usize,
/// The representative of this `VerifyingKey` in transcripts.
transcript_repr: C::Scalar,
/// Selectors
selectors: Vec<Vec<bool>>,
// TODO: Use setter/getter https://github.com/privacy-scaling-explorations/halo2/issues/259
/// Whether selector compression is turned on or not.
Expand Down
242 changes: 215 additions & 27 deletions halo2_backend/src/plonk/evaluation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! This module:
//! - Evaluates the h polynomial: Evaluator::new(ConstraintSystem).evaluate_h(...)
//! - Evaluates an Expression using Lagrange basis

use crate::multicore;
use crate::plonk::{lookup, permutation, ProvingKey};
use crate::poly::Basis;
use crate::poly::{Basis, LagrangeBasis};
use crate::{
arithmetic::{parallelize, CurveAffine},
poly::{Coeff, ExtendedLagrangeCoeff, Polynomial},
Expand All @@ -17,9 +21,9 @@
(((idx as i32) + (rot * rot_scale)).rem_euclid(isize)) as usize
}

/// Value used in a calculation
/// Value used in [`Calculation`]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
pub enum ValueSource {
enum ValueSource {
/// This is a constant value
Constant(usize),
/// This is an intermediate value
Expand Down Expand Up @@ -53,7 +57,7 @@
impl ValueSource {
/// Get the value for this source
#[allow(clippy::too_many_arguments)]
pub fn get<F: Field, B: Basis>(
fn get<F: Field, B: Basis>(
&self,
rotations: &[usize],
constants: &[F],
Expand Down Expand Up @@ -92,7 +96,7 @@

/// Calculation
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Calculation {
enum Calculation {
/// This is an addition
Add(ValueSource, ValueSource),
/// This is a subtraction
Expand All @@ -114,7 +118,7 @@
impl Calculation {
/// Get the resulting value of this calculation
#[allow(clippy::too_many_arguments)]
pub fn evaluate<F: Field, B: Basis>(
fn evaluate<F: Field, B: Basis>(
&self,
rotations: &[usize],
constants: &[F],
Expand Down Expand Up @@ -169,46 +173,59 @@
#[derive(Clone, Default, Debug)]
pub struct Evaluator<C: CurveAffine> {
/// Custom gates evalution
pub custom_gates: GraphEvaluator<C>,
custom_gates: GraphEvaluator<C>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were pub before the frontend-backend split:

pub custom_gates: GraphEvaluator<C>,
/// Lookups evalution
pub lookups: Vec<GraphEvaluator<C>>,
/// Shuffle evalution
pub shuffles: Vec<GraphEvaluator<C>>,

I wonder why...

I checked this and it comes from an improvement that Brecht did, so this is not inherited from zcash. I guess this was unneeded pub that was unnoticed.

/// Lookups evalution
pub lookups: Vec<GraphEvaluator<C>>,
lookups: Vec<GraphEvaluator<C>>,
/// Shuffle evalution
pub shuffles: Vec<GraphEvaluator<C>>,
shuffles: Vec<GraphEvaluator<C>>,
}

/// GraphEvaluator
/// The purpose of GraphEvaluator to is to collect a set of computations and compute them by making a graph of
/// its internal operations to avoid repeating computations.
///
/// Computations can be added in two ways:
///
/// - using [`Self::add_expression`] where expressions are added and internally turned into a graph.
/// A reference to the computation is returned in the form of [ `ValueSource::Itermediate`] reference

Check warning on line 189 in halo2_backend/src/plonk/evaluation.rs

View workflow job for this annotation

GitHub Actions / Intra-doc links

unresolved link to `ValueSource::Itermediate`
/// index.
/// - using [`Self::add_calculation`] where you can add only a single operation or a
/// [Horner polynomial evaluation](https://en.wikipedia.org/wiki/Horner's_method) by using
/// Calculation::Horner
///
/// Finally, call [`Self::evaluate`] to get the result of the last calculation added.
///
#[derive(Clone, Debug)]
pub struct GraphEvaluator<C: CurveAffine> {
struct GraphEvaluator<C: CurveAffine> {
/// Constants
pub constants: Vec<C::ScalarExt>,
constants: Vec<C::ScalarExt>,
/// Rotations
pub rotations: Vec<i32>,
rotations: Vec<i32>,
/// Calculations
pub calculations: Vec<CalculationInfo>,
calculations: Vec<CalculationInfo>,
/// Number of intermediates
pub num_intermediates: usize,
num_intermediates: usize,
}

/// EvaluationData
#[derive(Default, Debug)]
pub struct EvaluationData<C: CurveAffine> {
struct EvaluationData<C: CurveAffine> {
/// Intermediates
pub intermediates: Vec<C::ScalarExt>,
intermediates: Vec<C::ScalarExt>,
/// Rotations
pub rotations: Vec<usize>,
rotations: Vec<usize>,
}

/// CaluclationInfo
/// CalculationInfo contains a calculation to perform and in [`target`] the [`EvaluationData::intermediate`] where the value is going to be stored.

Check warning on line 218 in halo2_backend/src/plonk/evaluation.rs

View workflow job for this annotation

GitHub Actions / Intra-doc links

unresolved link to `target`

Check warning on line 218 in halo2_backend/src/plonk/evaluation.rs

View workflow job for this annotation

GitHub Actions / Intra-doc links

unresolved link to `EvaluationData::intermediate`
#[derive(Clone, Debug)]
pub struct CalculationInfo {
struct CalculationInfo {
/// Calculation
pub calculation: Calculation,
calculation: Calculation,
/// Target
pub target: usize,
target: usize,
}

impl<C: CurveAffine> Evaluator<C> {
/// Creates a new evaluation structure
/// Creates a new evaluation structure from a [`ConstraintSystem`]
pub fn new(cs: &ConstraintSystem<C::ScalarExt>) -> Self {
let mut ev = Evaluator::default();

Expand Down Expand Up @@ -776,15 +793,19 @@
}

/// Creates a new evaluation structure
pub fn instance(&self) -> EvaluationData<C> {
fn instance(&self) -> EvaluationData<C> {
EvaluationData {
intermediates: vec![C::ScalarExt::ZERO; self.num_intermediates],
rotations: vec![0usize; self.rotations.len()],
}
}

#[allow(clippy::too_many_arguments)]
pub fn evaluate<B: Basis>(
/// Fills the EvaluationData
/// .intermediaries with the evaluation the calculation
/// .rotations with the indexes of the polinomials after rotations
/// returns the value of last evaluation done.
fn evaluate<B: Basis>(
&self,
data: &mut EvaluationData<C>,
fixed: &[Polynomial<C::ScalarExt, B>],
Expand Down Expand Up @@ -832,8 +853,8 @@
}
}

/// Simple evaluation of an expression
pub fn evaluate<F: Field, B: Basis>(
/// Simple evaluation of an [`Expression`] over the provided lagrange polynomials
pub fn evaluate<F: Field, B: LagrangeBasis>(
CPerezz marked this conversation as resolved.
Show resolved Hide resolved
expression: &Expression<F>,
size: usize,
rot_scale: i32,
Expand Down Expand Up @@ -872,3 +893,170 @@
});
values
}

#[cfg(test)]
mod test {
use crate::poly::LagrangeCoeff;
use halo2_common::plonk::sealed::Phase;
use halo2_common::plonk::{AdviceQuery, Challenge, FixedQuery};
use halo2_common::plonk::{Expression, InstanceQuery};
use halo2_middleware::circuit::ChallengeMid;
use halo2_middleware::poly::Rotation;
use halo2curves::pasta::pallas::{Affine, Scalar};

use super::*;

fn check(calc: Option<Calculation>, expr: Option<Expression<Scalar>>, expected: i64) {
let lagranges = |v: &[&[u64]]| -> Vec<Polynomial<Scalar, LagrangeCoeff>> {
v.iter()
.map(|vv| {
Polynomial::new_lagrange_from_vec(
vv.iter().map(|v| Scalar::from(*v)).collect::<Vec<_>>(),
)
})
.collect()
};

let mut gv = GraphEvaluator::<Affine>::default();
if let Some(expression) = expr {
gv.add_expression(&expression);
} else if let Some(calculation) = calc {
gv.add_rotation(&Rotation::cur());
gv.add_rotation(&Rotation::next());
gv.add_calculation(calculation);
} else {
unreachable!()
}

let mut evaluation_data = gv.instance();
let result = gv.evaluate(
&mut evaluation_data,
&lagranges(&[&[2, 3], &[1002, 1003]]), // fixed
&lagranges(&[&[4, 5], &[1004, 1005]]), // advice
&lagranges(&[&[6, 7], &[1006, 1007]]), // instance
&[8u64.into(), 9u64.into()], // challenges
&Scalar::from_raw([10, 0, 0, 0]), // beta
&Scalar::from_raw([11, 0, 0, 0]), // gamma
&Scalar::from_raw([12, 0, 0, 0]), // theta
&Scalar::from_raw([13, 0, 0, 0]), // y
&Scalar::from_raw([14, 0, 0, 0]), // previous value
0, // idx
1, // rot_scale
32, // isize
);
let fq_expected = if expected < 0 {
-Scalar::from(-expected as u64)
} else {
Scalar::from(expected as u64)
};

assert_eq!(
result, fq_expected,
"Expected {} was {:?}",
expected, result
);
}
fn check_expr(expr: Expression<Scalar>, expected: i64) {
check(None, Some(expr), expected);
}
fn check_calc(calc: Calculation, expected: i64) {
check(Some(calc), None, expected);
}

#[test]
fn graphevaluator_values() {
// Check values
for (col, rot, expected) in [(0, 0, 2), (0, 1, 3), (1, 0, 1002), (1, 1, 1003)] {
check_expr(
Expression::Fixed(FixedQuery {
index: None,
column_index: col,
rotation: Rotation(rot),
}),
expected,
);
}
for (col, rot, expected) in [(0, 0, 4), (0, 1, 5), (1, 0, 1004), (1, 1, 1005)] {
check_expr(
Expression::Advice(AdviceQuery {
index: None,
column_index: col,
rotation: Rotation(rot),
phase: Phase(0),
}),
expected,
);
}
for (col, rot, expected) in [(0, 0, 6), (0, 1, 7), (1, 0, 1006), (1, 1, 1007)] {
check_expr(
Expression::Instance(InstanceQuery {
index: None,
column_index: col,
rotation: Rotation(rot),
}),
expected,
);
}
for (ch, expected) in [(0, 8), (1, 9)] {
check_expr(
Expression::Challenge(Challenge::from(ChallengeMid {
index: ch,
phase: 0,
})),
expected,
);
}

check_calc(Calculation::Store(ValueSource::Beta()), 10);
check_calc(Calculation::Store(ValueSource::Gamma()), 11);
check_calc(Calculation::Store(ValueSource::Theta()), 12);
check_calc(Calculation::Store(ValueSource::Y()), 13);
check_calc(Calculation::Store(ValueSource::PreviousValue()), 14);
}

#[test]
fn graphevaluator_expr_operations() {
// Check expression operations
let two = || {
Box::new(Expression::<Scalar>::Fixed(FixedQuery {
index: None,
column_index: 0,
rotation: Rotation(0),
}))
};

let three = || {
Box::new(Expression::<Scalar>::Fixed(FixedQuery {
index: None,
column_index: 0,
rotation: Rotation(1),
}))
};

check_expr(Expression::Sum(two(), three()), 5);
check_expr(Expression::Product(two(), three()), 6);
check_expr(Expression::Scaled(two(), Scalar::from(5)), 10);
check_expr(
Expression::Sum(Expression::Negated(two()).into(), three()),
1,
);
}

#[test]
fn graphevaluator_calc_operations() {
// Check calculation operations
let two = || ValueSource::Fixed(0, 0);
let three = || ValueSource::Fixed(0, 1);

check_calc(Calculation::Add(two(), three()), 5);
check_calc(Calculation::Double(two()), 4);
check_calc(Calculation::Mul(two(), three()), 6);
check_calc(Calculation::Square(three()), 9);
check_calc(Calculation::Negate(two()), -2);
check_calc(Calculation::Sub(three(), two()), 1);
check_calc(
Calculation::Horner(two(), vec![three(), two()], three()),
2 + 3 * 3 + 2 * 9,
);
}
}
Loading
Loading