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

Add some more explicit doc on plonky2 crate main components #1447

Merged
merged 8 commits into from
Jan 11, 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
4 changes: 2 additions & 2 deletions evm/src/curve_pairings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ where
}

/// Standard addition formula for elliptic curves, restricted to the cases
/// https://en.wikipedia.org/wiki/Elliptic_curve#Algebraic_interpretation
/// <https://en.wikipedia.org/wiki/Elliptic_curve#Algebraic_interpretation>
impl<T: FieldExt> Add for Curve<T> {
type Output = Self;

Expand Down Expand Up @@ -201,7 +201,7 @@ pub(crate) fn bn_tate(p: Curve<BN254>, q: Curve<Fp2<BN254>>) -> Fp12<BN254> {
}

/// Standard code for miller loop, can be found on page 99 at this url:
/// https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf#page=107
/// <https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf#page=107>
/// where BN_EXP is a hardcoding of the array of Booleans that the loop traverses
pub(crate) fn bn_miller_loop(p: Curve<BN254>, q: Curve<Fp2<BN254>>) -> Fp12<BN254> {
let mut r = p;
Expand Down
2 changes: 1 addition & 1 deletion evm/src/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl<F: Field> Lookup<F> {
}
}

/// logUp protocol from https://ia.cr/2022/1530
/// logUp protocol from <https://ia.cr/2022/1530>
/// Compute the helper columns for the lookup argument.
/// Given columns `f0,...,fk` and a column `t`, such that `∪fi ⊆ t`, and challenges `x`,
/// this computes the helper columns `h_i = 1/(x+f_2i) + 1/(x+f_2i+1)`, `g = 1/(x+t)`,
Expand Down
5 changes: 5 additions & 0 deletions plonky2/src/fri/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! Fast Reed-Solomon IOP (FRI) protocol.
//!
//! It provides both a native implementation and an in-circuit version
//! of the FRI verifier for recursive proof composition.
Nashtare marked this conversation as resolved.
Show resolved Hide resolved

use alloc::vec::Vec;

use serde::Serialize;
Expand Down
16 changes: 10 additions & 6 deletions plonky2/src/gadgets/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.arithmetic(F::ONE, F::ONE, x, one, y)
}

/// Add `n` `Target`s.
/// Adds `n` `Target`s.
pub fn add_many<T>(&mut self, terms: impl IntoIterator<Item = T>) -> Target
where
T: Borrow<Target>,
Expand Down Expand Up @@ -224,7 +224,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
.fold(self.one(), |acc, t| self.mul(acc, *t.borrow()))
}

/// Exponentiate `base` to the power of `2^power_log`.
/// Exponentiates `base` to the power of `2^power_log`.
pub fn exp_power_of_2(&mut self, base: Target, power_log: usize) -> Target {
if power_log > self.num_base_arithmetic_ops_per_gate() {
// Cheaper to just use `ExponentiateGate`.
Expand All @@ -239,7 +239,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}

// TODO: Test
/// Exponentiate `base` to the power of `exponent`, given by its little-endian bits.
/// Exponentiates `base` to the power of `exponent`, given by its little-endian bits.
pub fn exp_from_bits(
&mut self,
base: Target,
Expand All @@ -264,7 +264,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}

// TODO: Test
/// Exponentiate `base` to the power of `exponent`, where `exponent < 2^num_bits`.
/// Exponentiates `base` to the power of `exponent`, where `exponent < 2^num_bits`.
pub fn exp(&mut self, base: Target, exponent: Target, num_bits: usize) -> Target {
let exponent_bits = self.split_le(exponent, num_bits);

Expand Down Expand Up @@ -303,7 +303,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
product
}

/// Exponentiate `base` to the power of a known `exponent`.
/// Exponentiates `base` to the power of a known `exponent`.
// TODO: Test
pub fn exp_u64(&mut self, base: Target, mut exponent: u64) -> Target {
let mut exp_bits = Vec::new();
Expand All @@ -330,28 +330,32 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.inverse_extension(x_ext).0[0]
}

/// Computes the logical NOT of the provided [`BoolTarget`].
pub fn not(&mut self, b: BoolTarget) -> BoolTarget {
let one = self.one();
let res = self.sub(one, b.target);
BoolTarget::new_unsafe(res)
}

/// Computes the logical AND of the provided [`BoolTarget`]s.
pub fn and(&mut self, b1: BoolTarget, b2: BoolTarget) -> BoolTarget {
BoolTarget::new_unsafe(self.mul(b1.target, b2.target))
}

/// computes the arithmetic extension of logical "or": `b1 + b2 - b1 * b2`
/// Computes the logical OR through the arithmetic expression: `b1 + b2 - b1 * b2`.
pub fn or(&mut self, b1: BoolTarget, b2: BoolTarget) -> BoolTarget {
let res_minus_b2 = self.arithmetic(-F::ONE, F::ONE, b1.target, b2.target, b1.target);
BoolTarget::new_unsafe(self.add(res_minus_b2, b2.target))
}

/// Outputs `x` if `b` is true, and else `y`, through the formula: `b*x + (1-b)*y`.
pub fn _if(&mut self, b: BoolTarget, x: Target, y: Target) -> Target {
let not_b = self.not(b);
let maybe_x = self.mul(b.target, x);
self.mul_add(not_b.target, y, maybe_x)
}

/// Checks whether `x` and `y` are equal and outputs the boolean result.
pub fn is_equal(&mut self, x: Target, y: Target) -> BoolTarget {
let zero = self.zero();

Expand Down
4 changes: 4 additions & 0 deletions plonky2/src/gadgets/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! Helper gadgets providing additional methods to
//! [CircuitBuilder](crate::plonk::circuit_builder::CircuitBuilder),
//! to ease circuit creation.

pub mod arithmetic;
pub mod arithmetic_extension;
pub mod hash;
Expand Down
4 changes: 2 additions & 2 deletions plonky2/src/gates/arithmetic_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use crate::plonk::vars::{
};
use crate::util::serialization::{Buffer, IoResult, Read, Write};

/// A gate which can perform a weighted multiply-add, i.e. `result = c0 x y + c1 z`. If the config
/// supports enough routed wires, it can support several such operations in one gate.
/// A gate which can perform a weighted multiply-add, i.e. `result = c0.x.y + c1.z`. If the config
/// has enough routed wires, it can support several such operations in one gate.
#[derive(Debug, Clone)]
pub struct ArithmeticGate {
/// Number of arithmetic operations performed by an arithmetic gate.
Expand Down
4 changes: 2 additions & 2 deletions plonky2/src/gates/arithmetic_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData};
use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
use crate::util::serialization::{Buffer, IoResult, Read, Write};

/// A gate which can perform a weighted multiply-add, i.e. `result = c0 x y + c1 z`. If the config
/// supports enough routed wires, it can support several such operations in one gate.
/// A gate which can perform a weighted multiply-add, i.e. `result = c0.x.y + c1.z`. If the config
/// has enough routed wires, it can support several such operations in one gate.
#[derive(Debug, Clone)]
pub struct ArithmeticExtensionGate<const D: usize> {
/// Number of arithmetic operations performed by an arithmetic gate.
Expand Down
49 changes: 48 additions & 1 deletion plonky2/src/gates/gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,45 @@ use crate::plonk::vars::{
use crate::util::serialization::{Buffer, IoResult};

/// A custom gate.
///
/// Vanilla Plonk arithmetization only supports basic fan-in 2 / fan-out 1 arithmetic gates,
/// each of the form
///
/// $$ a.b.q_M + a.q_L + b.q_R + c.q_O + q_C = 0 $$
///
/// where:
/// - q_M, q_L, q_R and q_O are boolean selectors,
/// - a, b and c are values used as inputs and output respectively,
/// - q_C is a constant (possibly 0).
///
/// This allows expressing simple operations like multiplication, addition, etc. For
/// instance, to define a multiplication, one can set q_M=1, q_L=q_R=0, q_O = -1 and q_C = 0.
/// Hence, the gate equation simplifies to a.b - c = 0, or a.b = c.
///
/// However, such a gate is fairly limited for more complex computations. Hence, when a computation may
/// require too many of these "vanilla" gates, or when a computation arises often within the same circuit,
/// one may want to construct a tailored custom gate. These custom gates can use more selectors and are
/// not necessarily limited to 2 inputs + 1 output = 3 wires.
/// For instance, plonky2 supports natively a custom Poseidon hash gate that uses 135 wires.
///
/// Note however that extending the number of wires necessary for a custom gate comes at a price, and may
/// impact the overall performances when generating proofs for a circuit containing them.
pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + Sync {
/// Defines a unique identifier for this custom gate.
///
/// This is used as differentiating tag in gate serializers.
Nashtare marked this conversation as resolved.
Show resolved Hide resolved
fn id(&self) -> String;

/// Serializes this custom gate to the targeted byte buffer, with the provided [`CommonCircuitData`].
fn serialize(&self, dst: &mut Vec<u8>, common_data: &CommonCircuitData<F, D>) -> IoResult<()>;

/// Deserializes the bytes in the provided buffer into this custom gate, given some [`CommonCircuitData`].
fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData<F, D>) -> IoResult<Self>
where
Self: Sized;

/// Defines and evaluates the constraints that enforce the statement represented by this gate.
/// Constraints must be defined in the extension of this custom gate base field.
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension>;

/// Like `eval_unfiltered`, but specialized for points in the base field.
Expand Down Expand Up @@ -88,6 +118,12 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
res
}

/// Defines the recursive constraints that enforce the statement represented by this custom gate.
/// This is necessary to recursively verify proofs generated from a circuit containing such gates.
///
/// **Note**: The order of the recursive constraints output by this method should match exactly the order
/// of the constraints obtained by the non-recursive [`Gate::eval_unfiltered`] method, otherwise the
/// prover won't be able to generate proofs.
fn eval_unfiltered_circuit(
&self,
builder: &mut CircuitBuilder<F, D>,
Expand Down Expand Up @@ -175,10 +211,20 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
}

/// The generators used to populate the witness.
/// Note: This should return exactly 1 generator per operation in the gate.
///
/// **Note**: This should return exactly 1 generator per operation in the gate.
fn generators(&self, row: usize, local_constants: &[F]) -> Vec<WitnessGeneratorRef<F, D>>;

/// The number of wires used by this gate.
///
/// While vanilla Plonk can only evaluate one addition/multiplication at a time, a wider
/// configuration may be able to accomodate several identical gates at once. This is
/// particularly helpful for tiny custom gates that are being used extensively in circuits.
///
/// For instance, the [crate::gates::multiplication_extension::MulExtensionGate] takes `3*D`
/// wires per multiplication (where `D`` is the degree of the extension), hence for a usual
/// configuration of 80 routed wires with D=2, one can evaluate 13 multiplications within a
/// single gate.
fn num_wires(&self) -> usize;

/// The number of constants used by this gate.
Expand All @@ -187,6 +233,7 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
/// The maximum degree among this gate's constraint polynomials.
fn degree(&self) -> usize;

/// The number of constraints defined by this sole custom gate.
fn num_constraints(&self) -> usize;

/// Number of operations performed by the gate.
Expand Down
22 changes: 22 additions & 0 deletions plonky2/src/gates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
//! plonky2 custom gates.
//!
//! Vanilla Plonk arithmetization only supports basic fan-in 2 / fan-out 1 arithmetic gates,
//! each of the form
//!
//! $$ a.b.q_M + a.q_L + b.q_R + c.q_O + q_C = 0 $$
//!
//! where:
//! - q_M, q_L, q_R and q_O are boolean selectors,
//! - a, b and c are values used as inputs and output respectively,
//! - q_C is a constant (possibly 0).
//!
//! This allows expressing simple operations like multiplication, addition, etc. For
//! instance, to define a multiplication, one can set q_M=1, q_L=q_R=0, q_O = -1 and q_C = 0.
//! Hence, the gate equation simplifies to a.b - c = 0, or a.b = c.
//!
//! However, such a gate is fairly limited for more complex computations. Hence, when a computation may
//! require too many of these "vanilla" gates, or when a computation arises often within the same circuit,
//! one may want to construct a tailored custom gate. These custom gates can use more selectors and are
//! not necessarily limited to 2 inputs + 1 output = 3 wires.
//! For instance, plonky2 supports natively a custom Poseidon hash gate that uses 135 wires.

// Gates have `new` methods that return `GateRef`s.

pub mod arithmetic_base;
Expand Down
4 changes: 2 additions & 2 deletions plonky2/src/gates/multiplication_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData};
use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
use crate::util::serialization::{Buffer, IoResult, Read, Write};

/// A gate which can perform a weighted multiplication, i.e. `result = c0 x y`. If the config
/// supports enough routed wires, it can support several such operations in one gate.
/// A gate which can perform a weighted multiplication, i.e. `result = c0.x.y` on [`ExtensionTarget`].
/// If the config has enough routed wires, it can support several such operations in one gate.
#[derive(Debug, Clone)]
pub struct MulExtensionGate<const D: usize> {
/// Number of multiplications performed by the gate.
Expand Down
3 changes: 3 additions & 0 deletions plonky2/src/hash/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! plonky2 hashing logic for in-circuit hashing and Merkle proof verification
//! as well as specific hash functions implementation.

mod arch;
pub mod hash_types;
pub mod hashing;
Expand Down
4 changes: 4 additions & 0 deletions plonky2/src/iop/ext_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ use crate::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder;

/// `Target`s representing an element of an extension field.
///
/// This is typically used in recursion settings, where the outer circuit must verify
/// a proof satisfying an inner circuit's statement, which is verified using arithmetic
/// in an extension of the base field.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct ExtensionTarget<const D: usize>(pub [Target; D]);

Expand Down
16 changes: 13 additions & 3 deletions plonky2/src/iop/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,25 @@ use crate::iop::wire::Wire;
use crate::plonk::circuit_data::CircuitConfig;

/// A location in the witness.
///
/// Targets can either be placed at a specific location, or be "floating" around,
/// serving as intermediary value holders, and copied to other locations whenever needed.
///
/// When generating a proof for a given circuit, the prover will "set" the values of some
/// (or all) targets, so that they satisfy the circuit constraints. This is done through
/// the [PartialWitness](crate::iop::witness::PartialWitness) interface.
///
/// There are different "variants" of the `Target` type, namely [`ExtensionTarget`],
/// [ExtensionAlgebraTarget](crate::iop::ext_target::ExtensionAlgebraTarget).
/// The `Target` type is the default one for most circuits verifying some simple statement.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
pub enum Target {
/// A target that has a fixed location in the witness (seen as a `degree x num_wires` grid).
Wire(Wire),
/// A target that doesn't have any inherent location in the witness (but it can be copied to
/// another target that does). This is useful for representing intermediate values in witness
/// generation.
VirtualTarget {
index: usize,
},
VirtualTarget { index: usize },
}

impl Default for Target {
Expand Down
1 change: 1 addition & 0 deletions plonky2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

pub extern crate alloc;

/// Re-export of `plonky2_field`.
#[doc(inline)]
pub use plonky2_field as field;

Expand Down
Loading
Loading