mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-05 23:33:07 +00:00
Draw challenge points from the extension field (#51)
* Draw challenge points from the extension field * Now building * Misc * Default eval_unfiltered_base * fmt * A few field settings * Add to Sage * Display tweak * eval_filtered_base * Quartic in bench * Missing methods * Fix tests * PR feedback
This commit is contained in:
parent
15eb25bc35
commit
cb7f8c8b8c
@ -19,7 +19,7 @@ fn main() {
|
|||||||
// change this to info or warn later.
|
// change this to info or warn later.
|
||||||
env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init();
|
env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init();
|
||||||
|
|
||||||
bench_prove::<CrandallField, 2>();
|
bench_prove::<CrandallField, 4>();
|
||||||
|
|
||||||
// bench_field_mul::<CrandallField>();
|
// bench_field_mul::<CrandallField>();
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bench_prove<F: Field + Extendable<D>, const D: usize>() {
|
fn bench_prove<F: Field + Extendable<D>, const D: usize>() {
|
||||||
let gmimc_gate = GMiMCGate::<F, GMIMC_ROUNDS>::with_automatic_constants();
|
let gmimc_gate = GMiMCGate::<F, D, GMIMC_ROUNDS>::with_automatic_constants();
|
||||||
|
|
||||||
let config = CircuitConfig {
|
let config = CircuitConfig {
|
||||||
num_wires: 134,
|
num_wires: 134,
|
||||||
@ -46,7 +46,7 @@ fn bench_prove<F: Field + Extendable<D>, const D: usize>() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut builder = CircuitBuilder::<F>::new(config);
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
|
||||||
for _ in 0..10000 {
|
for _ in 0..10000 {
|
||||||
builder.add_gate_no_constants(gmimc_gate.clone());
|
builder.add_gate_no_constants(gmimc_gate.clone());
|
||||||
|
|||||||
@ -8,28 +8,28 @@ use crate::circuit_data::{
|
|||||||
VerifierCircuitData, VerifierOnlyCircuitData,
|
VerifierCircuitData, VerifierOnlyCircuitData,
|
||||||
};
|
};
|
||||||
use crate::field::cosets::get_unique_coset_shifts;
|
use crate::field::cosets::get_unique_coset_shifts;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::constant::ConstantGate;
|
use crate::gates::constant::ConstantGate;
|
||||||
use crate::gates::gate::{GateInstance, GateRef};
|
use crate::gates::gate::{GateInstance, GateRef};
|
||||||
use crate::gates::noop::NoopGate;
|
use crate::gates::noop::NoopGate;
|
||||||
use crate::generator::{CopyGenerator, WitnessGenerator};
|
use crate::generator::{CopyGenerator, WitnessGenerator};
|
||||||
use crate::hash::hash_n_to_hash;
|
use crate::hash::hash_n_to_hash;
|
||||||
use crate::merkle_tree::MerkleTree;
|
|
||||||
use crate::permutation_argument::TargetPartitions;
|
use crate::permutation_argument::TargetPartitions;
|
||||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||||
use crate::polynomial::polynomial::PolynomialValues;
|
use crate::polynomial::polynomial::PolynomialValues;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::util::{log2_strict, transpose, transpose_poly_values};
|
use crate::util::{log2_strict, transpose};
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
|
|
||||||
pub struct CircuitBuilder<F: Field> {
|
pub struct CircuitBuilder<F: Extendable<D>, const D: usize> {
|
||||||
pub(crate) config: CircuitConfig,
|
pub(crate) config: CircuitConfig,
|
||||||
|
|
||||||
/// The types of gates used in this circuit.
|
/// The types of gates used in this circuit.
|
||||||
gates: HashSet<GateRef<F>>,
|
gates: HashSet<GateRef<F, D>>,
|
||||||
|
|
||||||
/// The concrete placement of each gate.
|
/// The concrete placement of each gate.
|
||||||
gate_instances: Vec<GateInstance<F>>,
|
gate_instances: Vec<GateInstance<F, D>>,
|
||||||
|
|
||||||
/// The next available index for a public input.
|
/// The next available index for a public input.
|
||||||
public_input_index: usize,
|
public_input_index: usize,
|
||||||
@ -46,7 +46,7 @@ pub struct CircuitBuilder<F: Field> {
|
|||||||
targets_to_constants: HashMap<Target, F>,
|
targets_to_constants: HashMap<Target, F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
pub fn new(config: CircuitConfig) -> Self {
|
pub fn new(config: CircuitConfig) -> Self {
|
||||||
CircuitBuilder {
|
CircuitBuilder {
|
||||||
config,
|
config,
|
||||||
@ -89,12 +89,12 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
(0..n).map(|_i| self.add_virtual_advice_target()).collect()
|
(0..n).map(|_i| self.add_virtual_advice_target()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_gate_no_constants(&mut self, gate_type: GateRef<F>) -> usize {
|
pub fn add_gate_no_constants(&mut self, gate_type: GateRef<F, D>) -> usize {
|
||||||
self.add_gate(gate_type, Vec::new())
|
self.add_gate(gate_type, Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a gate to the circuit, and returns its index.
|
/// Adds a gate to the circuit, and returns its index.
|
||||||
pub fn add_gate(&mut self, gate_type: GateRef<F>, constants: Vec<F>) -> usize {
|
pub fn add_gate(&mut self, gate_type: GateRef<F, D>, constants: Vec<F>) -> usize {
|
||||||
// If we haven't seen a gate of this type before, check that it's compatible with our
|
// If we haven't seen a gate of this type before, check that it's compatible with our
|
||||||
// circuit configuration, then register it.
|
// circuit configuration, then register it.
|
||||||
if !self.gates.contains(&gate_type) {
|
if !self.gates.contains(&gate_type) {
|
||||||
@ -113,7 +113,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_gate_compatibility(&self, gate: &GateRef<F>) {
|
fn check_gate_compatibility(&self, gate: &GateRef<F, D>) {
|
||||||
assert!(
|
assert!(
|
||||||
gate.0.num_wires() <= self.config.num_wires,
|
gate.0.num_wires() <= self.config.num_wires,
|
||||||
"{:?} requires {} wires, but our GateConfig has only {}",
|
"{:?} requires {} wires, but our GateConfig has only {}",
|
||||||
@ -261,7 +261,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a "full circuit", with both prover and verifier data.
|
/// Builds a "full circuit", with both prover and verifier data.
|
||||||
pub fn build(mut self) -> CircuitData<F> {
|
pub fn build(mut self) -> CircuitData<F, D> {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
info!(
|
info!(
|
||||||
"degree before blinding & padding: {}",
|
"degree before blinding & padding: {}",
|
||||||
@ -335,7 +335,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a "prover circuit", with data needed to generate proofs but not verify them.
|
/// Builds a "prover circuit", with data needed to generate proofs but not verify them.
|
||||||
pub fn build_prover(self) -> ProverCircuitData<F> {
|
pub fn build_prover(self) -> ProverCircuitData<F, D> {
|
||||||
// TODO: Can skip parts of this.
|
// TODO: Can skip parts of this.
|
||||||
let CircuitData {
|
let CircuitData {
|
||||||
prover_only,
|
prover_only,
|
||||||
@ -349,7 +349,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a "verifier circuit", with data needed to verify proofs but not generate them.
|
/// Builds a "verifier circuit", with data needed to verify proofs but not generate them.
|
||||||
pub fn build_verifier(self) -> VerifierCircuitData<F> {
|
pub fn build_verifier(self) -> VerifierCircuitData<F, D> {
|
||||||
// TODO: Can skip parts of this.
|
// TODO: Can skip parts of this.
|
||||||
let CircuitData {
|
let CircuitData {
|
||||||
verifier_only,
|
verifier_only,
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use crate::field::field::Field;
|
|||||||
use crate::fri::FriConfig;
|
use crate::fri::FriConfig;
|
||||||
use crate::gates::gate::GateRef;
|
use crate::gates::gate::GateRef;
|
||||||
use crate::generator::WitnessGenerator;
|
use crate::generator::WitnessGenerator;
|
||||||
use crate::merkle_tree::MerkleTree;
|
|
||||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||||
use crate::proof::{Hash, HashTarget, Proof};
|
use crate::proof::{Hash, HashTarget, Proof};
|
||||||
use crate::prover::prove;
|
use crate::prover::prove;
|
||||||
@ -52,24 +51,18 @@ impl CircuitConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Circuit data required by the prover or the verifier.
|
/// Circuit data required by the prover or the verifier.
|
||||||
pub struct CircuitData<F: Field> {
|
pub struct CircuitData<F: Extendable<D>, const D: usize> {
|
||||||
pub(crate) prover_only: ProverOnlyCircuitData<F>,
|
pub(crate) prover_only: ProverOnlyCircuitData<F>,
|
||||||
pub(crate) verifier_only: VerifierOnlyCircuitData<F>,
|
pub(crate) verifier_only: VerifierOnlyCircuitData<F>,
|
||||||
pub(crate) common: CommonCircuitData<F>,
|
pub(crate) common: CommonCircuitData<F, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> CircuitData<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitData<F, D> {
|
||||||
pub fn prove<const D: usize>(&self, inputs: PartialWitness<F>) -> Proof<F, D>
|
pub fn prove(&self, inputs: PartialWitness<F>) -> Proof<F, D> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
prove(&self.prover_only, &self.common, inputs)
|
prove(&self.prover_only, &self.common, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify<const D: usize>(&self, proof: Proof<F, D>) -> Result<()>
|
pub fn verify(&self, proof: Proof<F, D>) -> Result<()> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
verify(proof, &self.verifier_only, &self.common)
|
verify(proof, &self.verifier_only, &self.common)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,31 +74,25 @@ impl<F: Field> CircuitData<F> {
|
|||||||
/// structure as succinct as we can. Thus we include various precomputed data which isn't strictly
|
/// structure as succinct as we can. Thus we include various precomputed data which isn't strictly
|
||||||
/// required, like LDEs of preprocessed polynomials. If more succinctness was desired, we could
|
/// required, like LDEs of preprocessed polynomials. If more succinctness was desired, we could
|
||||||
/// construct a more minimal prover structure and convert back and forth.
|
/// construct a more minimal prover structure and convert back and forth.
|
||||||
pub struct ProverCircuitData<F: Field> {
|
pub struct ProverCircuitData<F: Extendable<D>, const D: usize> {
|
||||||
pub(crate) prover_only: ProverOnlyCircuitData<F>,
|
pub(crate) prover_only: ProverOnlyCircuitData<F>,
|
||||||
pub(crate) common: CommonCircuitData<F>,
|
pub(crate) common: CommonCircuitData<F, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> ProverCircuitData<F> {
|
impl<F: Extendable<D>, const D: usize> ProverCircuitData<F, D> {
|
||||||
pub fn prove<const D: usize>(&self, inputs: PartialWitness<F>) -> Proof<F, D>
|
pub fn prove(&self, inputs: PartialWitness<F>) -> Proof<F, D> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
prove(&self.prover_only, &self.common, inputs)
|
prove(&self.prover_only, &self.common, inputs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Circuit data required by the prover.
|
/// Circuit data required by the prover.
|
||||||
pub struct VerifierCircuitData<F: Field> {
|
pub struct VerifierCircuitData<F: Extendable<D>, const D: usize> {
|
||||||
pub(crate) verifier_only: VerifierOnlyCircuitData<F>,
|
pub(crate) verifier_only: VerifierOnlyCircuitData<F>,
|
||||||
pub(crate) common: CommonCircuitData<F>,
|
pub(crate) common: CommonCircuitData<F, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> VerifierCircuitData<F> {
|
impl<F: Extendable<D>, const D: usize> VerifierCircuitData<F, D> {
|
||||||
pub fn verify<const D: usize>(&self, proof: Proof<F, D>) -> Result<()>
|
pub fn verify(&self, proof: Proof<F, D>) -> Result<()> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
verify(proof, &self.verifier_only, &self.common)
|
verify(proof, &self.verifier_only, &self.common)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,13 +116,13 @@ pub(crate) struct VerifierOnlyCircuitData<F: Field> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Circuit data required by both the prover and the verifier.
|
/// Circuit data required by both the prover and the verifier.
|
||||||
pub(crate) struct CommonCircuitData<F: Field> {
|
pub(crate) struct CommonCircuitData<F: Extendable<D>, const D: usize> {
|
||||||
pub(crate) config: CircuitConfig,
|
pub(crate) config: CircuitConfig,
|
||||||
|
|
||||||
pub(crate) degree_bits: usize,
|
pub(crate) degree_bits: usize,
|
||||||
|
|
||||||
/// The types of gates used in this circuit.
|
/// The types of gates used in this circuit.
|
||||||
pub(crate) gates: Vec<GateRef<F>>,
|
pub(crate) gates: Vec<GateRef<F, D>>,
|
||||||
|
|
||||||
/// The largest number of constraints imposed by any gate.
|
/// The largest number of constraints imposed by any gate.
|
||||||
pub(crate) num_gate_constraints: usize,
|
pub(crate) num_gate_constraints: usize,
|
||||||
@ -148,7 +135,7 @@ pub(crate) struct CommonCircuitData<F: Field> {
|
|||||||
pub(crate) circuit_digest: Hash<F>,
|
pub(crate) circuit_digest: Hash<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> CommonCircuitData<F> {
|
impl<F: Extendable<D>, const D: usize> CommonCircuitData<F, D> {
|
||||||
pub fn degree(&self) -> usize {
|
pub fn degree(&self) -> usize {
|
||||||
1 << self.degree_bits
|
1 << self.degree_bits
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::field::field::Field;
|
|||||||
|
|
||||||
pub mod quadratic;
|
pub mod quadratic;
|
||||||
pub mod quartic;
|
pub mod quartic;
|
||||||
|
mod quartic_quartic;
|
||||||
pub mod target;
|
pub mod target;
|
||||||
|
|
||||||
/// Optimal extension field trait.
|
/// Optimal extension field trait.
|
||||||
@ -32,7 +33,7 @@ impl<F: Field> OEF<1> for F {
|
|||||||
const W: Self::BaseField = F::ZERO;
|
const W: Self::BaseField = F::ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Extendable<const D: usize>: Sized {
|
pub trait Extendable<const D: usize>: Field + Sized {
|
||||||
type Extension: Field + OEF<D, BaseField = Self> + From<Self>;
|
type Extension: Field + OEF<D, BaseField = Self> + From<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,11 @@ use crate::field::extension_field::{FieldExtension, OEF};
|
|||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
use std::iter::{Product, Sum};
|
use std::iter::{Product, Sum};
|
||||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct QuadraticCrandallField([CrandallField; 2]);
|
pub struct QuadraticCrandallField([CrandallField; 2]);
|
||||||
|
|
||||||
impl OEF<2> for QuadraticCrandallField {
|
impl OEF<2> for QuadraticCrandallField {
|
||||||
@ -38,23 +38,6 @@ impl From<<Self as FieldExtension<2>>::BaseField> for QuadraticCrandallField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for QuadraticCrandallField {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
FieldExtension::<2>::to_basefield_array(self)
|
|
||||||
== FieldExtension::<2>::to_basefield_array(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for QuadraticCrandallField {}
|
|
||||||
|
|
||||||
impl Hash for QuadraticCrandallField {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
for l in &FieldExtension::<2>::to_basefield_array(self) {
|
|
||||||
Hash::hash(l, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Field for QuadraticCrandallField {
|
impl Field for QuadraticCrandallField {
|
||||||
const ZERO: Self = Self([CrandallField::ZERO; 2]);
|
const ZERO: Self = Self([CrandallField::ZERO; 2]);
|
||||||
const ONE: Self = Self([CrandallField::ONE, CrandallField::ZERO]);
|
const ONE: Self = Self([CrandallField::ONE, CrandallField::ZERO]);
|
||||||
|
|||||||
@ -1,18 +1,23 @@
|
|||||||
use crate::field::crandall_field::CrandallField;
|
|
||||||
use crate::field::extension_field::{FieldExtension, OEF};
|
|
||||||
use crate::field::field::Field;
|
|
||||||
use rand::Rng;
|
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
use std::iter::{Product, Sum};
|
use std::iter::{Product, Sum};
|
||||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
use rand::Rng;
|
||||||
pub struct QuarticCrandallField([CrandallField; 4]);
|
|
||||||
|
use crate::field::crandall_field::CrandallField;
|
||||||
|
use crate::field::extension_field::quartic_quartic::QuarticQuarticCrandallField;
|
||||||
|
use crate::field::extension_field::{Extendable, FieldExtension, OEF};
|
||||||
|
use crate::field::field::Field;
|
||||||
|
|
||||||
|
/// A quartic extension of `CrandallField`.
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct QuarticCrandallField(pub(crate) [CrandallField; 4]);
|
||||||
|
|
||||||
impl OEF<4> for QuarticCrandallField {
|
impl OEF<4> for QuarticCrandallField {
|
||||||
// Verifiable in Sage with
|
// Verifiable in Sage with
|
||||||
// ``R.<x> = GF(p)[]; assert (x^4 -3).is_irreducible()`.
|
// R.<x> = GF(p)[]
|
||||||
|
// assert (x^4 - 3).is_irreducible()
|
||||||
const W: CrandallField = CrandallField(3);
|
const W: CrandallField = CrandallField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,23 +48,6 @@ impl From<<Self as FieldExtension<4>>::BaseField> for QuarticCrandallField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for QuarticCrandallField {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
FieldExtension::<4>::to_basefield_array(self)
|
|
||||||
== FieldExtension::<4>::to_basefield_array(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for QuarticCrandallField {}
|
|
||||||
|
|
||||||
impl Hash for QuarticCrandallField {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
for l in &FieldExtension::<4>::to_basefield_array(self) {
|
|
||||||
Hash::hash(l, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Field for QuarticCrandallField {
|
impl Field for QuarticCrandallField {
|
||||||
const ZERO: Self = Self([CrandallField::ZERO; 4]);
|
const ZERO: Self = Self([CrandallField::ZERO; 4]);
|
||||||
const ONE: Self = Self([
|
const ONE: Self = Self([
|
||||||
@ -251,6 +239,10 @@ impl DivAssign for QuarticCrandallField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Extendable<4> for QuarticCrandallField {
|
||||||
|
type Extension = QuarticQuarticCrandallField;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||||
|
|||||||
259
src/field/extension_field/quartic_quartic.rs
Normal file
259
src/field/extension_field/quartic_quartic.rs
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
use crate::field::crandall_field::CrandallField;
|
||||||
|
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||||
|
use crate::field::extension_field::{FieldExtension, OEF};
|
||||||
|
use crate::field::field::Field;
|
||||||
|
use rand::Rng;
|
||||||
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::iter::{Product, Sum};
|
||||||
|
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
|
|
||||||
|
/// A quartic extension of `QuarticCrandallField`.
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct QuarticQuarticCrandallField(pub(crate) [QuarticCrandallField; 4]);
|
||||||
|
|
||||||
|
impl OEF<4> for QuarticQuarticCrandallField {
|
||||||
|
// Verifiable in Sage with
|
||||||
|
// p = 2^64 - 9 * 2^28 + 1
|
||||||
|
// F = GF(p)
|
||||||
|
// PR_F.<x> = PolynomialRing(F)
|
||||||
|
// assert (x^4 - 3).is_irreducible()
|
||||||
|
// F4.<y> = F.extension(x^4 - 3)
|
||||||
|
// PR_F4.<z> = PolynomialRing(F4)
|
||||||
|
// assert (x^4 - y).is_irreducible()
|
||||||
|
// F44.<w> = F4.extension(x^4 - y)
|
||||||
|
const W: QuarticCrandallField = QuarticCrandallField([
|
||||||
|
CrandallField(0),
|
||||||
|
CrandallField(1),
|
||||||
|
CrandallField(0),
|
||||||
|
CrandallField(0),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FieldExtension<4> for QuarticQuarticCrandallField {
|
||||||
|
type BaseField = QuarticCrandallField;
|
||||||
|
|
||||||
|
fn to_basefield_array(&self) -> [Self::BaseField; 4] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_basefield_array(arr: [Self::BaseField; 4]) -> Self {
|
||||||
|
Self(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_basefield(x: Self::BaseField) -> Self {
|
||||||
|
x.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<<Self as FieldExtension<4>>::BaseField> for QuarticQuarticCrandallField {
|
||||||
|
fn from(x: <Self as FieldExtension<4>>::BaseField) -> Self {
|
||||||
|
Self([
|
||||||
|
x,
|
||||||
|
<Self as FieldExtension<4>>::BaseField::ZERO,
|
||||||
|
<Self as FieldExtension<4>>::BaseField::ZERO,
|
||||||
|
<Self as FieldExtension<4>>::BaseField::ZERO,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field for QuarticQuarticCrandallField {
|
||||||
|
const ZERO: Self = Self([QuarticCrandallField::ZERO; 4]);
|
||||||
|
const ONE: Self = Self([
|
||||||
|
QuarticCrandallField::ONE,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
]);
|
||||||
|
const TWO: Self = Self([
|
||||||
|
QuarticCrandallField::TWO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
]);
|
||||||
|
const NEG_ONE: Self = Self([
|
||||||
|
QuarticCrandallField::NEG_ONE,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Does not fit in 64-bits.
|
||||||
|
const ORDER: u64 = 0;
|
||||||
|
const TWO_ADICITY: usize = 32;
|
||||||
|
const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([
|
||||||
|
QuarticCrandallField([
|
||||||
|
CrandallField(7562951059982399618),
|
||||||
|
CrandallField(16734862117167184487),
|
||||||
|
CrandallField(8532193866847630013),
|
||||||
|
CrandallField(15462716295551021898),
|
||||||
|
]),
|
||||||
|
QuarticCrandallField([
|
||||||
|
CrandallField(16143979237658148445),
|
||||||
|
CrandallField(12004617499933809221),
|
||||||
|
CrandallField(11826153143854535879),
|
||||||
|
CrandallField(14780824604953232397),
|
||||||
|
]),
|
||||||
|
QuarticCrandallField([
|
||||||
|
CrandallField(12779077039546101185),
|
||||||
|
CrandallField(15745975127331074164),
|
||||||
|
CrandallField(4297791107105154033),
|
||||||
|
CrandallField(5966855376644799108),
|
||||||
|
]),
|
||||||
|
QuarticCrandallField([
|
||||||
|
CrandallField(1942992936904935291),
|
||||||
|
CrandallField(6041097781717465159),
|
||||||
|
CrandallField(16875726992388585780),
|
||||||
|
CrandallField(17742746479895474446),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
const POWER_OF_TWO_GENERATOR: Self = Self([
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField([
|
||||||
|
CrandallField::ZERO,
|
||||||
|
CrandallField::ZERO,
|
||||||
|
CrandallField::ZERO,
|
||||||
|
CrandallField(6809469153480715254),
|
||||||
|
]),
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
QuarticCrandallField::ZERO,
|
||||||
|
]);
|
||||||
|
|
||||||
|
fn try_inverse(&self) -> Option<Self> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_canonical_u64(&self) -> u64 {
|
||||||
|
panic!("Doesn't fit!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_canonical_u64(n: u64) -> Self {
|
||||||
|
<Self as FieldExtension<4>>::BaseField::from_canonical_u64(n).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rand_from_rng<R: Rng>(rng: &mut R) -> Self {
|
||||||
|
Self([
|
||||||
|
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||||
|
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||||
|
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||||
|
<Self as FieldExtension<4>>::BaseField::rand_from_rng(rng),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for QuarticQuarticCrandallField {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"({}) + ({})*b + ({})*b^2 + ({})*b^3",
|
||||||
|
self.0[0], self.0[1], self.0[2], self.0[3]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for QuarticQuarticCrandallField {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for QuarticQuarticCrandallField {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn neg(self) -> Self {
|
||||||
|
Self([-self.0[0], -self.0[1], -self.0[2], -self.0[3]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for QuarticQuarticCrandallField {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, rhs: Self) -> Self {
|
||||||
|
Self([
|
||||||
|
self.0[0] + rhs.0[0],
|
||||||
|
self.0[1] + rhs.0[1],
|
||||||
|
self.0[2] + rhs.0[2],
|
||||||
|
self.0[3] + rhs.0[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for QuarticQuarticCrandallField {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self + rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sum for QuarticQuarticCrandallField {
|
||||||
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(Self::ZERO, |acc, x| acc + x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for QuarticQuarticCrandallField {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sub(self, rhs: Self) -> Self {
|
||||||
|
Self([
|
||||||
|
self.0[0] - rhs.0[0],
|
||||||
|
self.0[1] - rhs.0[1],
|
||||||
|
self.0[2] - rhs.0[2],
|
||||||
|
self.0[3] - rhs.0[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for QuarticQuarticCrandallField {
|
||||||
|
#[inline]
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self - rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for QuarticQuarticCrandallField {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, rhs: Self) -> Self {
|
||||||
|
let Self([a0, a1, a2, a3]) = self;
|
||||||
|
let Self([b0, b1, b2, b3]) = rhs;
|
||||||
|
|
||||||
|
let c0 = a0 * b0 + <Self as OEF<4>>::W * (a1 * b3 + a2 * b2 + a3 * b1);
|
||||||
|
let c1 = a0 * b1 + a1 * b0 + <Self as OEF<4>>::W * (a2 * b3 + a3 * b2);
|
||||||
|
let c2 = a0 * b2 + a1 * b1 + a2 * b0 + <Self as OEF<4>>::W * a3 * b3;
|
||||||
|
let c3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||||
|
|
||||||
|
Self([c0, c1, c2, c3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for QuarticQuarticCrandallField {
|
||||||
|
#[inline]
|
||||||
|
fn mul_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self * rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Product for QuarticQuarticCrandallField {
|
||||||
|
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
|
iter.fold(Self::ONE, |acc, x| acc * x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for QuarticQuarticCrandallField {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
self * rhs.inverse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DivAssign for QuarticQuarticCrandallField {
|
||||||
|
fn div_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self / rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ use crate::field::extension_field::{Extendable, FieldExtension, OEF};
|
|||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
|
|
||||||
|
/// `Target`s representing an element of an extension field.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ExtensionTarget<const D: usize>(pub [Target; D]);
|
pub struct ExtensionTarget<const D: usize>(pub [Target; D]);
|
||||||
|
|
||||||
@ -12,50 +13,117 @@ impl<const D: usize> ExtensionTarget<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
/// `Target`s representing an element of an extension of an extension field.
|
||||||
pub fn zero_extension<const D: usize>(&mut self) -> ExtensionTarget<D>
|
#[derive(Copy, Clone, Debug)]
|
||||||
where
|
pub struct ExtensionExtensionTarget<const D: usize>(pub [ExtensionTarget<D>; D]);
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
impl<const D: usize> ExtensionExtensionTarget<D> {
|
||||||
ExtensionTarget([self.zero(); D])
|
pub fn to_ext_target_array(&self) -> [ExtensionTarget<D>; D] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
|
pub fn constant_extension(&mut self, c: F::Extension) -> ExtensionTarget<D> {
|
||||||
|
let c_parts = c.to_basefield_array();
|
||||||
|
let mut parts = [self.zero(); D];
|
||||||
|
for i in 0..D {
|
||||||
|
parts[i] = self.constant(c_parts[i]);
|
||||||
|
}
|
||||||
|
ExtensionTarget(parts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_extension<const D: usize>(
|
pub fn constant_ext_ext(
|
||||||
|
&mut self,
|
||||||
|
c: <<F as Extendable<D>>::Extension as Extendable<D>>::Extension,
|
||||||
|
) -> ExtensionExtensionTarget<D>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
|
let c_parts = c.to_basefield_array();
|
||||||
|
let mut parts = [self.zero_extension(); D];
|
||||||
|
for i in 0..D {
|
||||||
|
parts[i] = self.constant_extension(c_parts[i]);
|
||||||
|
}
|
||||||
|
ExtensionExtensionTarget(parts)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zero_extension(&mut self) -> ExtensionTarget<D> {
|
||||||
|
self.constant_extension(F::Extension::ZERO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn one_extension(&mut self) -> ExtensionTarget<D> {
|
||||||
|
self.constant_extension(F::Extension::ONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn two_extension(&mut self) -> ExtensionTarget<D> {
|
||||||
|
self.constant_extension(F::Extension::TWO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zero_ext_ext(&mut self) -> ExtensionExtensionTarget<D>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
|
self.constant_ext_ext(<<F as Extendable<D>>::Extension as Extendable<D>>::Extension::ZERO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_extension(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut a: ExtensionTarget<D>,
|
mut a: ExtensionTarget<D>,
|
||||||
b: ExtensionTarget<D>,
|
b: ExtensionTarget<D>,
|
||||||
) -> ExtensionTarget<D>
|
) -> ExtensionTarget<D> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
for i in 0..D {
|
for i in 0..D {
|
||||||
a.0[i] = self.add(a.0[i], b.0[i]);
|
a.0[i] = self.add(a.0[i], b.0[i]);
|
||||||
}
|
}
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_extension<const D: usize>(
|
pub fn add_ext_ext(
|
||||||
|
&mut self,
|
||||||
|
mut a: ExtensionExtensionTarget<D>,
|
||||||
|
b: ExtensionExtensionTarget<D>,
|
||||||
|
) -> ExtensionExtensionTarget<D> {
|
||||||
|
for i in 0..D {
|
||||||
|
a.0[i] = self.add_extension(a.0[i], b.0[i]);
|
||||||
|
}
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_many_extension(&mut self, terms: &[ExtensionTarget<D>]) -> ExtensionTarget<D> {
|
||||||
|
let mut sum = self.zero_extension();
|
||||||
|
for term in terms {
|
||||||
|
sum = self.add_extension(sum, *term);
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_extension(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut a: ExtensionTarget<D>,
|
mut a: ExtensionTarget<D>,
|
||||||
b: ExtensionTarget<D>,
|
b: ExtensionTarget<D>,
|
||||||
) -> ExtensionTarget<D>
|
) -> ExtensionTarget<D> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
for i in 0..D {
|
for i in 0..D {
|
||||||
a.0[i] = self.sub(a.0[i], b.0[i]);
|
a.0[i] = self.sub(a.0[i], b.0[i]);
|
||||||
}
|
}
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mul_extension<const D: usize>(
|
pub fn sub_ext_ext(
|
||||||
|
&mut self,
|
||||||
|
mut a: ExtensionExtensionTarget<D>,
|
||||||
|
b: ExtensionExtensionTarget<D>,
|
||||||
|
) -> ExtensionExtensionTarget<D> {
|
||||||
|
for i in 0..D {
|
||||||
|
a.0[i] = self.sub_extension(a.0[i], b.0[i]);
|
||||||
|
}
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_extension(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: ExtensionTarget<D>,
|
a: ExtensionTarget<D>,
|
||||||
b: ExtensionTarget<D>,
|
b: ExtensionTarget<D>,
|
||||||
) -> ExtensionTarget<D>
|
) -> ExtensionTarget<D> {
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
let mut res = [self.zero(); D];
|
let mut res = [self.zero(); D];
|
||||||
for i in 0..D {
|
for i in 0..D {
|
||||||
for j in 0..D {
|
for j in 0..D {
|
||||||
@ -70,18 +138,72 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
ExtensionTarget(res)
|
ExtensionTarget(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a*b where `b` is in the extension field and `a` is in the base field.
|
pub fn mul_ext_ext(
|
||||||
pub fn scalar_mul<const D: usize>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
a: Target,
|
mut a: ExtensionExtensionTarget<D>,
|
||||||
mut b: ExtensionTarget<D>,
|
b: ExtensionExtensionTarget<D>,
|
||||||
) -> ExtensionTarget<D>
|
) -> ExtensionExtensionTarget<D>
|
||||||
where
|
where
|
||||||
F: Extendable<D>,
|
F::Extension: Extendable<D>,
|
||||||
{
|
{
|
||||||
|
let mut res = [self.zero_extension(); D];
|
||||||
|
let w = self
|
||||||
|
.constant_extension(<<F as Extendable<D>>::Extension as Extendable<D>>::Extension::W);
|
||||||
|
for i in 0..D {
|
||||||
|
for j in 0..D {
|
||||||
|
let ai_bi = self.mul_extension(a.0[i], b.0[j]);
|
||||||
|
res[(i + j) % D] = if i + j < D {
|
||||||
|
self.add_extension(ai_bi, res[(i + j) % D])
|
||||||
|
} else {
|
||||||
|
let w_ai_bi = self.mul_extension(w, ai_bi);
|
||||||
|
self.add_extension(w_ai_bi, res[(i + j) % D])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExtensionExtensionTarget(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul_many_extension(&mut self, terms: &[ExtensionTarget<D>]) -> ExtensionTarget<D> {
|
||||||
|
let mut product = self.one_extension();
|
||||||
|
for term in terms {
|
||||||
|
product = self.mul_extension(product, *term);
|
||||||
|
}
|
||||||
|
product
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `mul_add`, but for `ExtensionTarget`s. Note that, unlike `mul_add`, this has no
|
||||||
|
/// performance benefit over separate muls and adds.
|
||||||
|
pub fn mul_add_extension(
|
||||||
|
&mut self,
|
||||||
|
a: ExtensionTarget<D>,
|
||||||
|
b: ExtensionTarget<D>,
|
||||||
|
c: ExtensionTarget<D>,
|
||||||
|
) -> ExtensionTarget<D> {
|
||||||
|
let product = self.mul_extension(a, b);
|
||||||
|
self.add_extension(product, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `a * b`, where `b` is in the extension field and `a` is in the base field.
|
||||||
|
pub fn scalar_mul_ext(&mut self, a: Target, mut b: ExtensionTarget<D>) -> ExtensionTarget<D> {
|
||||||
for i in 0..D {
|
for i in 0..D {
|
||||||
b.0[i] = self.mul(a, b.0[i]);
|
b.0[i] = self.mul(a, b.0[i]);
|
||||||
}
|
}
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `a * b`, where `b` is in the extension of the extension field, and `a` is in the
|
||||||
|
/// extension field.
|
||||||
|
pub fn scalar_mul_ext_ext(
|
||||||
|
&mut self,
|
||||||
|
a: ExtensionTarget<D>,
|
||||||
|
mut b: ExtensionExtensionTarget<D>,
|
||||||
|
) -> ExtensionExtensionTarget<D>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
|
for i in 0..D {
|
||||||
|
b.0[i] = self.mul_extension(a, b.0[i]);
|
||||||
|
}
|
||||||
|
b
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,12 +50,12 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use anyhow::Result;
|
||||||
|
use rand::rngs::ThreadRng;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::field::crandall_field::CrandallField;
|
use crate::field::crandall_field::CrandallField;
|
||||||
use crate::field::extension_field::quadratic::QuadraticCrandallField;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
|
||||||
use crate::field::extension_field::{flatten, Extendable, FieldExtension};
|
|
||||||
use crate::field::fft::ifft;
|
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::fri::prover::fri_proof;
|
use crate::fri::prover::fri_proof;
|
||||||
use crate::fri::verifier::verify_fri_proof;
|
use crate::fri::verifier::verify_fri_proof;
|
||||||
@ -63,9 +63,8 @@ mod tests {
|
|||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
use crate::util::reverse_index_bits_in_place;
|
use crate::util::reverse_index_bits_in_place;
|
||||||
use anyhow::Result;
|
|
||||||
use rand::rngs::ThreadRng;
|
use super::*;
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
fn check_fri<F: Field + Extendable<D>, const D: usize>(
|
fn check_fri<F: Field + Extendable<D>, const D: usize>(
|
||||||
degree_log: usize,
|
degree_log: usize,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::arithmetic::ArithmeticGate;
|
use crate::gates::arithmetic::ArithmeticGate;
|
||||||
use crate::generator::SimpleGenerator;
|
use crate::generator::SimpleGenerator;
|
||||||
@ -6,7 +7,7 @@ use crate::target::Target;
|
|||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
/// Computes `-x`.
|
/// Computes `-x`.
|
||||||
pub fn neg(&mut self, x: Target) -> Target {
|
pub fn neg(&mut self, x: Target) -> Target {
|
||||||
let neg_one = self.neg_one();
|
let neg_one = self.neg_one();
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
use crate::field::field::Field;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::gates::gmimc::GMiMCGate;
|
use crate::gates::gmimc::GMiMCGate;
|
||||||
use crate::hash::GMIMC_ROUNDS;
|
use crate::hash::GMIMC_ROUNDS;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
|
|
||||||
// TODO: Move to be next to native `permute`?
|
// TODO: Move to be next to native `permute`?
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
pub fn permute(&mut self, inputs: [Target; 12]) -> [Target; 12] {
|
pub fn permute(&mut self, inputs: [Target; 12]) -> [Target; 12] {
|
||||||
let zero = self.zero();
|
let zero = self.zero();
|
||||||
let gate =
|
let gate =
|
||||||
self.add_gate_no_constants(GMiMCGate::<F, GMIMC_ROUNDS>::with_automatic_constants());
|
self.add_gate_no_constants(GMiMCGate::<F, D, GMIMC_ROUNDS>::with_automatic_constants());
|
||||||
|
|
||||||
// We don't want to swap any inputs, so set that wire to 0.
|
// We don't want to swap any inputs, so set that wire to 0.
|
||||||
let swap_wire = GMiMCGate::<F, GMIMC_ROUNDS>::WIRE_SWAP;
|
let swap_wire = GMiMCGate::<F, D, GMIMC_ROUNDS>::WIRE_SWAP;
|
||||||
let swap_wire = Target::Wire(Wire {
|
let swap_wire = Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: swap_wire,
|
input: swap_wire,
|
||||||
@ -24,7 +24,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
|
|
||||||
// The old accumulator wire doesn't matter, since we won't read the new accumulator wire.
|
// The old accumulator wire doesn't matter, since we won't read the new accumulator wire.
|
||||||
// We do have to set it to something though, so we'll arbitrary pick 0.
|
// We do have to set it to something though, so we'll arbitrary pick 0.
|
||||||
let old_acc_wire = GMiMCGate::<F, GMIMC_ROUNDS>::WIRE_INDEX_ACCUMULATOR_OLD;
|
let old_acc_wire = GMiMCGate::<F, D, GMIMC_ROUNDS>::WIRE_INDEX_ACCUMULATOR_OLD;
|
||||||
let old_acc_wire = Target::Wire(Wire {
|
let old_acc_wire = Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: old_acc_wire,
|
input: old_acc_wire,
|
||||||
@ -33,7 +33,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
|
|
||||||
// Route input wires.
|
// Route input wires.
|
||||||
for i in 0..12 {
|
for i in 0..12 {
|
||||||
let in_wire = GMiMCGate::<F, GMIMC_ROUNDS>::wire_input(i);
|
let in_wire = GMiMCGate::<F, D, GMIMC_ROUNDS>::wire_input(i);
|
||||||
let in_wire = Target::Wire(Wire {
|
let in_wire = Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: in_wire,
|
input: in_wire,
|
||||||
@ -46,7 +46,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
.map(|i| {
|
.map(|i| {
|
||||||
Target::Wire(Wire {
|
Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_output(i),
|
input: GMiMCGate::<F, D, GMIMC_ROUNDS>::wire_output(i),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|||||||
@ -1,28 +1,27 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
use crate::field::extension_field::target::ExtensionTarget;
|
use crate::field::extension_field::target::{ExtensionExtensionTarget, ExtensionTarget};
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
|
|
||||||
pub struct PolynomialCoeffsTarget<const D: usize>(pub Vec<ExtensionTarget<D>>);
|
pub struct PolynomialCoeffsExtTarget<const D: usize>(pub Vec<ExtensionTarget<D>>);
|
||||||
|
|
||||||
impl<const D: usize> PolynomialCoeffsTarget<D> {
|
impl<const D: usize> PolynomialCoeffsExtTarget<D> {
|
||||||
pub fn eval_scalar<F: Field + Extendable<D>>(
|
pub fn eval_scalar<F: Extendable<D>>(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
point: Target,
|
point: Target,
|
||||||
) -> ExtensionTarget<D> {
|
) -> ExtensionTarget<D> {
|
||||||
let mut acc = builder.zero_extension();
|
let mut acc = builder.zero_extension();
|
||||||
for &c in self.0.iter().rev() {
|
for &c in self.0.iter().rev() {
|
||||||
let tmp = builder.scalar_mul(point, acc);
|
let tmp = builder.scalar_mul_ext(point, acc);
|
||||||
acc = builder.add_extension(tmp, c);
|
acc = builder.add_extension(tmp, c);
|
||||||
}
|
}
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval<F: Field + Extendable<D>>(
|
pub fn eval<F: Extendable<D>>(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
point: ExtensionTarget<D>,
|
point: ExtensionTarget<D>,
|
||||||
) -> ExtensionTarget<D> {
|
) -> ExtensionTarget<D> {
|
||||||
let mut acc = builder.zero_extension();
|
let mut acc = builder.zero_extension();
|
||||||
@ -33,3 +32,41 @@ impl<const D: usize> PolynomialCoeffsTarget<D> {
|
|||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PolynomialCoeffsExtExtTarget<const D: usize>(pub Vec<ExtensionExtensionTarget<D>>);
|
||||||
|
|
||||||
|
impl<const D: usize> PolynomialCoeffsExtExtTarget<D> {
|
||||||
|
pub fn eval_scalar<F>(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
point: ExtensionTarget<D>,
|
||||||
|
) -> ExtensionExtensionTarget<D>
|
||||||
|
where
|
||||||
|
F: Extendable<D>,
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
|
let mut acc = builder.zero_ext_ext();
|
||||||
|
for &c in self.0.iter().rev() {
|
||||||
|
let tmp = builder.scalar_mul_ext_ext(point, acc);
|
||||||
|
acc = builder.add_ext_ext(tmp, c);
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval<F>(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
point: ExtensionExtensionTarget<D>,
|
||||||
|
) -> ExtensionExtensionTarget<D>
|
||||||
|
where
|
||||||
|
F: Extendable<D>,
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
|
let mut acc = builder.zero_ext_ext();
|
||||||
|
for &c in self.0.iter().rev() {
|
||||||
|
let tmp = builder.mul_ext_ext(point, acc);
|
||||||
|
acc = builder.add_ext_ext(tmp, c);
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
/// Split the given integer into a list of virtual advice targets, where each one represents a
|
/// Split the given integer into a list of virtual advice targets, where each one represents a
|
||||||
/// bit of the integer, with little-endian ordering.
|
/// bit of the integer, with little-endian ordering.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
||||||
@ -16,7 +18,7 @@ use crate::witness::PartialWitness;
|
|||||||
pub struct ArithmeticGate;
|
pub struct ArithmeticGate;
|
||||||
|
|
||||||
impl ArithmeticGate {
|
impl ArithmeticGate {
|
||||||
pub fn new<F: Field>() -> GateRef<F> {
|
pub fn new<F: Extendable<D>, const D: usize>() -> GateRef<F, D> {
|
||||||
GateRef::new(ArithmeticGate)
|
GateRef::new(ArithmeticGate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,12 +28,12 @@ impl ArithmeticGate {
|
|||||||
pub const WIRE_OUTPUT: usize = 3;
|
pub const WIRE_OUTPUT: usize = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Gate<F> for ArithmeticGate {
|
impl<F: Extendable<D>, const D: usize> Gate<F, D> for ArithmeticGate {
|
||||||
fn id(&self) -> String {
|
fn id(&self) -> String {
|
||||||
format!("{:?}", self)
|
format!("{:?}", self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unfiltered(&self, vars: EvaluationVars<F>) -> Vec<F> {
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
let const_0 = vars.local_constants[0];
|
let const_0 = vars.local_constants[0];
|
||||||
let const_1 = vars.local_constants[1];
|
let const_1 = vars.local_constants[1];
|
||||||
let multiplicand_0 = vars.local_wires[Self::WIRE_MULTIPLICAND_0];
|
let multiplicand_0 = vars.local_wires[Self::WIRE_MULTIPLICAND_0];
|
||||||
@ -44,9 +46,9 @@ impl<F: Field> Gate<F> for ArithmeticGate {
|
|||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
fn eval_unfiltered_recursively(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
let const_0 = vars.local_constants[0];
|
let const_0 = vars.local_constants[0];
|
||||||
let const_1 = vars.local_constants[1];
|
let const_1 = vars.local_constants[1];
|
||||||
let multiplicand_0 = vars.local_wires[Self::WIRE_MULTIPLICAND_0];
|
let multiplicand_0 = vars.local_wires[Self::WIRE_MULTIPLICAND_0];
|
||||||
@ -54,10 +56,10 @@ impl<F: Field> Gate<F> for ArithmeticGate {
|
|||||||
let addend = vars.local_wires[Self::WIRE_ADDEND];
|
let addend = vars.local_wires[Self::WIRE_ADDEND];
|
||||||
let output = vars.local_wires[Self::WIRE_OUTPUT];
|
let output = vars.local_wires[Self::WIRE_OUTPUT];
|
||||||
|
|
||||||
let product_term = builder.mul_many(&[const_0, multiplicand_0, multiplicand_1]);
|
let product_term = builder.mul_many_extension(&[const_0, multiplicand_0, multiplicand_1]);
|
||||||
let addend_term = builder.mul(const_1, addend);
|
let addend_term = builder.mul_extension(const_1, addend);
|
||||||
let computed_output = builder.add_many(&[product_term, addend_term]);
|
let computed_output = builder.add_many_extension(&[product_term, addend_term]);
|
||||||
vec![builder.sub(computed_output, output)]
|
vec![builder.sub_extension(computed_output, output)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generators(
|
fn generators(
|
||||||
@ -150,6 +152,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn low_degree() {
|
fn low_degree() {
|
||||||
test_low_degree(ArithmeticGate::new::<CrandallField>())
|
test_low_degree(ArithmeticGate::new::<CrandallField, 4>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
||||||
@ -11,7 +13,7 @@ use crate::witness::PartialWitness;
|
|||||||
pub struct ConstantGate;
|
pub struct ConstantGate;
|
||||||
|
|
||||||
impl ConstantGate {
|
impl ConstantGate {
|
||||||
pub fn get<F: Field>() -> GateRef<F> {
|
pub fn get<F: Extendable<D>, const D: usize>() -> GateRef<F, D> {
|
||||||
GateRef::new(ConstantGate)
|
GateRef::new(ConstantGate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,12 +22,12 @@ impl ConstantGate {
|
|||||||
pub const WIRE_OUTPUT: usize = 0;
|
pub const WIRE_OUTPUT: usize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Gate<F> for ConstantGate {
|
impl<F: Extendable<D>, const D: usize> Gate<F, D> for ConstantGate {
|
||||||
fn id(&self) -> String {
|
fn id(&self) -> String {
|
||||||
"ConstantGate".into()
|
"ConstantGate".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unfiltered(&self, vars: EvaluationVars<F>) -> Vec<F> {
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
let input = vars.local_constants[Self::CONST_INPUT];
|
let input = vars.local_constants[Self::CONST_INPUT];
|
||||||
let output = vars.local_wires[Self::WIRE_OUTPUT];
|
let output = vars.local_wires[Self::WIRE_OUTPUT];
|
||||||
vec![output - input]
|
vec![output - input]
|
||||||
@ -33,12 +35,12 @@ impl<F: Field> Gate<F> for ConstantGate {
|
|||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
fn eval_unfiltered_recursively(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
let input = vars.local_constants[Self::CONST_INPUT];
|
let input = vars.local_constants[Self::CONST_INPUT];
|
||||||
let output = vars.local_wires[Self::WIRE_OUTPUT];
|
let output = vars.local_wires[Self::WIRE_OUTPUT];
|
||||||
vec![builder.sub(output, input)]
|
vec![builder.sub_extension(output, input)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generators(
|
fn generators(
|
||||||
@ -98,6 +100,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn low_degree() {
|
fn low_degree() {
|
||||||
test_low_degree(ConstantGate::get::<CrandallField>())
|
test_low_degree(ConstantGate::get::<CrandallField, 4>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,33 +2,71 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
use crate::field::field::Field;
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::generator::WitnessGenerator;
|
use crate::generator::WitnessGenerator;
|
||||||
use crate::target::Target;
|
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
|
||||||
|
|
||||||
/// A custom gate.
|
/// A custom gate.
|
||||||
pub trait Gate<F: Field>: 'static + Send + Sync {
|
pub trait Gate<F: Extendable<D>, const D: usize>: 'static + Send + Sync {
|
||||||
fn id(&self) -> String;
|
fn id(&self) -> String;
|
||||||
|
|
||||||
fn eval_unfiltered(&self, vars: EvaluationVars<F>) -> Vec<F>;
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension>;
|
||||||
|
|
||||||
|
/// Like `eval_unfiltered`, but specialized for points in the base field.
|
||||||
|
///
|
||||||
|
/// By default, this just calls `eval_unfiltered`, which treats the point as an extension field
|
||||||
|
/// element. This isn't very efficient.
|
||||||
|
fn eval_unfiltered_base(&self, vars_base: EvaluationVarsBase<F>) -> Vec<F> {
|
||||||
|
let local_constants = &vars_base
|
||||||
|
.local_constants
|
||||||
|
.iter()
|
||||||
|
.map(|c| F::Extension::from_basefield(*c))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let local_wires = &vars_base
|
||||||
|
.local_wires
|
||||||
|
.iter()
|
||||||
|
.map(|w| F::Extension::from_basefield(*w))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let vars = EvaluationVars {
|
||||||
|
local_constants,
|
||||||
|
local_wires,
|
||||||
|
};
|
||||||
|
let values = self.eval_unfiltered(vars);
|
||||||
|
|
||||||
|
// Each value should be in the base field, i.e. only the degree-zero part should be nonzero.
|
||||||
|
values
|
||||||
|
.into_iter()
|
||||||
|
.map(|value| {
|
||||||
|
// TODO: Change to debug-only once our gate code is mostly finished/stable.
|
||||||
|
assert!(F::Extension::is_in_basefield(&value));
|
||||||
|
value.to_basefield_array()[0]
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
fn eval_unfiltered_recursively(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target>;
|
) -> Vec<ExtensionTarget<D>>;
|
||||||
|
|
||||||
fn eval_filtered(&self, vars: EvaluationVars<F>) -> Vec<F> {
|
fn eval_filtered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
// TODO: Filter
|
// TODO: Filter
|
||||||
self.eval_unfiltered(vars)
|
self.eval_unfiltered(vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like `eval_filtered`, but specialized for points in the base field.
|
||||||
|
fn eval_filtered_base(&self, vars: EvaluationVarsBase<F>) -> Vec<F> {
|
||||||
|
// TODO: Filter
|
||||||
|
self.eval_unfiltered_base(vars)
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_filtered_recursively(
|
fn eval_filtered_recursively(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
// TODO: Filter
|
// TODO: Filter
|
||||||
self.eval_unfiltered_recursively(builder, vars)
|
self.eval_unfiltered_recursively(builder, vars)
|
||||||
}
|
}
|
||||||
@ -53,30 +91,30 @@ pub trait Gate<F: Field>: 'static + Send + Sync {
|
|||||||
|
|
||||||
/// A wrapper around an `Rc<Gate>` which implements `PartialEq`, `Eq` and `Hash` based on gate IDs.
|
/// A wrapper around an `Rc<Gate>` which implements `PartialEq`, `Eq` and `Hash` based on gate IDs.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GateRef<F: Field>(pub(crate) Arc<dyn Gate<F>>);
|
pub struct GateRef<F: Extendable<D>, const D: usize>(pub(crate) Arc<dyn Gate<F, D>>);
|
||||||
|
|
||||||
impl<F: Field> GateRef<F> {
|
impl<F: Extendable<D>, const D: usize> GateRef<F, D> {
|
||||||
pub fn new<G: Gate<F>>(gate: G) -> GateRef<F> {
|
pub fn new<G: Gate<F, D>>(gate: G) -> GateRef<F, D> {
|
||||||
GateRef(Arc::new(gate))
|
GateRef(Arc::new(gate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> PartialEq for GateRef<F> {
|
impl<F: Extendable<D>, const D: usize> PartialEq for GateRef<F, D> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0.id() == other.0.id()
|
self.0.id() == other.0.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Hash for GateRef<F> {
|
impl<F: Extendable<D>, const D: usize> Hash for GateRef<F, D> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.0.id().hash(state)
|
self.0.id().hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Eq for GateRef<F> {}
|
impl<F: Extendable<D>, const D: usize> Eq for GateRef<F, D> {}
|
||||||
|
|
||||||
/// A gate along with any constants used to configure it.
|
/// A gate along with any constants used to configure it.
|
||||||
pub struct GateInstance<F: Field> {
|
pub struct GateInstance<F: Extendable<D>, const D: usize> {
|
||||||
pub gate_type: GateRef<F>,
|
pub gate_type: GateRef<F, D>,
|
||||||
pub constants: Vec<F>,
|
pub constants: Vec<F>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
@ -9,12 +10,12 @@ const WITNESS_DEGREE: usize = WITNESS_SIZE - 1;
|
|||||||
|
|
||||||
/// Tests that the constraints imposed by the given gate are low-degree by applying them to random
|
/// Tests that the constraints imposed by the given gate are low-degree by applying them to random
|
||||||
/// low-degree witness polynomials.
|
/// low-degree witness polynomials.
|
||||||
pub(crate) fn test_low_degree<F: Field>(gate: GateRef<F>) {
|
pub(crate) fn test_low_degree<F: Extendable<D>, const D: usize>(gate: GateRef<F, D>) {
|
||||||
let gate = gate.0;
|
let gate = gate.0;
|
||||||
let rate_bits = log2_ceil(gate.degree() + 1);
|
let rate_bits = log2_ceil(gate.degree() + 1);
|
||||||
|
|
||||||
let wire_ldes = random_low_degree_matrix(gate.num_wires(), rate_bits);
|
let wire_ldes = random_low_degree_matrix::<F::Extension>(gate.num_wires(), rate_bits);
|
||||||
let constant_ldes = random_low_degree_matrix::<F>(gate.num_constants(), rate_bits);
|
let constant_ldes = random_low_degree_matrix::<F::Extension>(gate.num_constants(), rate_bits);
|
||||||
assert_eq!(wire_ldes.len(), constant_ldes.len());
|
assert_eq!(wire_ldes.len(), constant_ldes.len());
|
||||||
|
|
||||||
let constraint_evals = wire_ldes
|
let constraint_evals = wire_ldes
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::gates::gmimc_eval::GMiMCEvalGate;
|
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
||||||
use crate::gmimc::gmimc_automatic_constants;
|
use crate::gmimc::gmimc_automatic_constants;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
@ -22,17 +23,17 @@ const W: usize = 12;
|
|||||||
/// sibling digests. It also has an accumulator that computes the weighted sum of these flags, for
|
/// sibling digests. It also has an accumulator that computes the weighted sum of these flags, for
|
||||||
/// computing the index of the leaf based on these swap bits.
|
/// computing the index of the leaf based on these swap bits.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GMiMCGate<F: Field, const R: usize> {
|
pub struct GMiMCGate<F: Extendable<D>, const D: usize, const R: usize> {
|
||||||
constants: Arc<[F; R]>,
|
constants: Arc<[F; R]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field, const R: usize> GMiMCGate<F, R> {
|
impl<F: Extendable<D>, const D: usize, const R: usize> GMiMCGate<F, D, R> {
|
||||||
pub fn with_constants(constants: Arc<[F; R]>) -> GateRef<F> {
|
pub fn with_constants(constants: Arc<[F; R]>) -> GateRef<F, D> {
|
||||||
let gate = GMiMCGate::<F, R> { constants };
|
let gate = GMiMCGate::<F, D, R> { constants };
|
||||||
GateRef::new(gate)
|
GateRef::new(gate)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_automatic_constants() -> GateRef<F> {
|
pub fn with_automatic_constants() -> GateRef<F, D> {
|
||||||
let constants = Arc::new(gmimc_automatic_constants::<F, R>());
|
let constants = Arc::new(gmimc_automatic_constants::<F, R>());
|
||||||
Self::with_constants(constants)
|
Self::with_constants(constants)
|
||||||
}
|
}
|
||||||
@ -66,21 +67,21 @@ impl<F: Field, const R: usize> GMiMCGate<F, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field, const R: usize> Gate<F> for GMiMCGate<F, R> {
|
impl<F: Extendable<D>, const D: usize, const R: usize> Gate<F, D> for GMiMCGate<F, D, R> {
|
||||||
fn id(&self) -> String {
|
fn id(&self) -> String {
|
||||||
format!("<R={}> {:?}", R, self)
|
format!("<R={}> {:?}", R, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unfiltered(&self, vars: EvaluationVars<F>) -> Vec<F> {
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
||||||
|
|
||||||
// Assert that `swap` is binary.
|
// Assert that `swap` is binary.
|
||||||
let swap = vars.local_wires[Self::WIRE_SWAP];
|
let swap = vars.local_wires[Self::WIRE_SWAP];
|
||||||
constraints.push(swap * (swap - F::ONE));
|
constraints.push(swap * (swap - F::Extension::ONE));
|
||||||
|
|
||||||
let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD];
|
let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD];
|
||||||
let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW];
|
let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW];
|
||||||
let computed_new_index_acc = F::TWO * old_index_acc + swap;
|
let computed_new_index_acc = F::Extension::TWO * old_index_acc + swap;
|
||||||
constraints.push(computed_new_index_acc - new_index_acc);
|
constraints.push(computed_new_index_acc - new_index_acc);
|
||||||
|
|
||||||
let mut state = Vec::with_capacity(12);
|
let mut state = Vec::with_capacity(12);
|
||||||
@ -100,11 +101,11 @@ impl<F: Field, const R: usize> Gate<F> for GMiMCGate<F, R> {
|
|||||||
|
|
||||||
// Value that is implicitly added to each element.
|
// Value that is implicitly added to each element.
|
||||||
// See https://affine.group/2020/02/starkware-challenge
|
// See https://affine.group/2020/02/starkware-challenge
|
||||||
let mut addition_buffer = F::ZERO;
|
let mut addition_buffer = F::Extension::ZERO;
|
||||||
|
|
||||||
for r in 0..R {
|
for r in 0..R {
|
||||||
let active = r % W;
|
let active = r % W;
|
||||||
let cubing_input = state[active] + addition_buffer + self.constants[r];
|
let cubing_input = state[active] + addition_buffer + self.constants[r].into();
|
||||||
let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)];
|
let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)];
|
||||||
constraints.push(cubing_input - cubing_input_wire);
|
constraints.push(cubing_input - cubing_input_wire);
|
||||||
let f = cubing_input_wire.cube();
|
let f = cubing_input_wire.cube();
|
||||||
@ -122,37 +123,36 @@ impl<F: Field, const R: usize> Gate<F> for GMiMCGate<F, R> {
|
|||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
fn eval_unfiltered_recursively(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
||||||
|
|
||||||
// Assert that `swap` is binary. Usually we would assert that
|
|
||||||
// swap(swap - 1) = 0
|
|
||||||
// but to make it work with a single ArithmeticGate, we will instead write it as
|
|
||||||
// swap*swap - swap = 0
|
|
||||||
let swap = vars.local_wires[Self::WIRE_SWAP];
|
let swap = vars.local_wires[Self::WIRE_SWAP];
|
||||||
constraints.push(builder.mul_sub(swap, swap, swap));
|
let one_ext = builder.one_extension();
|
||||||
|
let not_swap = builder.sub_extension(swap, one_ext);
|
||||||
|
constraints.push(builder.mul_extension(swap, not_swap));
|
||||||
|
|
||||||
let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD];
|
let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD];
|
||||||
let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW];
|
let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW];
|
||||||
// computed_new_index_acc = 2 * old_index_acc + swap
|
// computed_new_index_acc = 2 * old_index_acc + swap
|
||||||
let two = builder.two();
|
let two = builder.two();
|
||||||
let computed_new_index_acc = builder.mul_add(two, old_index_acc, swap);
|
let double_old_index_acc = builder.scalar_mul_ext(two, old_index_acc);
|
||||||
constraints.push(builder.sub(computed_new_index_acc, new_index_acc));
|
let computed_new_index_acc = builder.add_extension(double_old_index_acc, swap);
|
||||||
|
constraints.push(builder.sub_extension(computed_new_index_acc, new_index_acc));
|
||||||
|
|
||||||
let mut state = Vec::with_capacity(12);
|
let mut state = Vec::with_capacity(12);
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
let a = vars.local_wires[i];
|
let a = vars.local_wires[i];
|
||||||
let b = vars.local_wires[i + 4];
|
let b = vars.local_wires[i + 4];
|
||||||
let delta = builder.sub(b, a);
|
let delta = builder.sub_extension(b, a);
|
||||||
state.push(builder.mul_add(swap, delta, a));
|
state.push(builder.mul_add_extension(swap, delta, a));
|
||||||
}
|
}
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
let a = vars.local_wires[i + 4];
|
let a = vars.local_wires[i + 4];
|
||||||
let b = vars.local_wires[i];
|
let b = vars.local_wires[i];
|
||||||
let delta = builder.sub(b, a);
|
let delta = builder.sub_extension(b, a);
|
||||||
state.push(builder.mul_add(swap, delta, a));
|
state.push(builder.mul_add_extension(swap, delta, a));
|
||||||
}
|
}
|
||||||
for i in 8..12 {
|
for i in 8..12 {
|
||||||
state.push(vars.local_wires[i]);
|
state.push(vars.local_wires[i]);
|
||||||
@ -160,56 +160,24 @@ impl<F: Field, const R: usize> Gate<F> for GMiMCGate<F, R> {
|
|||||||
|
|
||||||
// Value that is implicitly added to each element.
|
// Value that is implicitly added to each element.
|
||||||
// See https://affine.group/2020/02/starkware-challenge
|
// See https://affine.group/2020/02/starkware-challenge
|
||||||
let mut addition_buffer = builder.zero();
|
let mut addition_buffer = builder.zero_extension();
|
||||||
|
|
||||||
for r in 0..R {
|
for r in 0..R {
|
||||||
let active = r % W;
|
let active = r % W;
|
||||||
let gate = builder.add_gate(GMiMCEvalGate::get(), vec![self.constants[r]]);
|
|
||||||
|
|
||||||
let cubing_input = vars.local_wires[Self::wire_cubing_input(r)];
|
let constant = builder.constant_extension(self.constants[r].into());
|
||||||
builder.route(
|
let cubing_input =
|
||||||
cubing_input,
|
builder.add_many_extension(&[state[active], addition_buffer, constant]);
|
||||||
Target::Wire(Wire {
|
let square = builder.mul_extension(cubing_input, cubing_input);
|
||||||
gate,
|
let f = builder.mul_extension(square, cubing_input);
|
||||||
input: GMiMCEvalGate::<F>::WIRE_CUBING_INPUT,
|
addition_buffer = builder.add_extension(addition_buffer, f);
|
||||||
}),
|
state[active] = builder.sub_extension(state[active], f);
|
||||||
);
|
|
||||||
|
|
||||||
builder.route(
|
|
||||||
addition_buffer,
|
|
||||||
Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_ADDITION_BUFFER_OLD,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.route(
|
|
||||||
state[active],
|
|
||||||
Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_STATE_A_OLD,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
constraints.push(Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_CONSTRAINT,
|
|
||||||
}));
|
|
||||||
|
|
||||||
addition_buffer = Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_ADDITION_BUFFER_NEW,
|
|
||||||
});
|
|
||||||
|
|
||||||
state[active] = Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_STATE_A_NEW,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..W {
|
for i in 0..W {
|
||||||
state[i] = builder.add(state[i], addition_buffer);
|
state[i] = builder.add_extension(state[i], addition_buffer);
|
||||||
constraints.push(builder.sub(state[i], vars.local_wires[Self::wire_output(i)]));
|
constraints
|
||||||
|
.push(builder.sub_extension(state[i], vars.local_wires[Self::wire_output(i)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
constraints
|
constraints
|
||||||
@ -245,19 +213,21 @@ impl<F: Field, const R: usize> Gate<F> for GMiMCGate<F, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct GMiMCGenerator<F: Field, const R: usize> {
|
struct GMiMCGenerator<F: Extendable<D>, const D: usize, const R: usize> {
|
||||||
gate_index: usize,
|
gate_index: usize,
|
||||||
constants: Arc<[F; R]>,
|
constants: Arc<[F; R]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
|
impl<F: Extendable<D>, const D: usize, const R: usize> SimpleGenerator<F>
|
||||||
|
for GMiMCGenerator<F, D, R>
|
||||||
|
{
|
||||||
fn dependencies(&self) -> Vec<Target> {
|
fn dependencies(&self) -> Vec<Target> {
|
||||||
let mut dep_input_indices = Vec::with_capacity(W + 2);
|
let mut dep_input_indices = Vec::with_capacity(W + 2);
|
||||||
for i in 0..W {
|
for i in 0..W {
|
||||||
dep_input_indices.push(GMiMCGate::<F, R>::wire_input(i));
|
dep_input_indices.push(GMiMCGate::<F, D, R>::wire_input(i));
|
||||||
}
|
}
|
||||||
dep_input_indices.push(GMiMCGate::<F, R>::WIRE_SWAP);
|
dep_input_indices.push(GMiMCGate::<F, D, R>::WIRE_SWAP);
|
||||||
dep_input_indices.push(GMiMCGate::<F, R>::WIRE_INDEX_ACCUMULATOR_OLD);
|
dep_input_indices.push(GMiMCGate::<F, D, R>::WIRE_INDEX_ACCUMULATOR_OLD);
|
||||||
|
|
||||||
dep_input_indices
|
dep_input_indices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -277,14 +247,14 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
|
|||||||
.map(|i| {
|
.map(|i| {
|
||||||
witness.get_wire(Wire {
|
witness.get_wire(Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: GMiMCGate::<F, R>::wire_input(i),
|
input: GMiMCGate::<F, D, R>::wire_input(i),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let swap_value = witness.get_wire(Wire {
|
let swap_value = witness.get_wire(Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: GMiMCGate::<F, R>::WIRE_SWAP,
|
input: GMiMCGate::<F, D, R>::WIRE_SWAP,
|
||||||
});
|
});
|
||||||
debug_assert!(swap_value == F::ZERO || swap_value == F::ONE);
|
debug_assert!(swap_value == F::ZERO || swap_value == F::ONE);
|
||||||
if swap_value == F::ONE {
|
if swap_value == F::ONE {
|
||||||
@ -296,13 +266,13 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
|
|||||||
// Update the index accumulator.
|
// Update the index accumulator.
|
||||||
let old_index_acc_value = witness.get_wire(Wire {
|
let old_index_acc_value = witness.get_wire(Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: GMiMCGate::<F, R>::WIRE_INDEX_ACCUMULATOR_OLD,
|
input: GMiMCGate::<F, D, R>::WIRE_INDEX_ACCUMULATOR_OLD,
|
||||||
});
|
});
|
||||||
let new_index_acc_value = F::TWO * old_index_acc_value + swap_value;
|
let new_index_acc_value = F::TWO * old_index_acc_value + swap_value;
|
||||||
result.set_wire(
|
result.set_wire(
|
||||||
Wire {
|
Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: GMiMCGate::<F, R>::WIRE_INDEX_ACCUMULATOR_NEW,
|
input: GMiMCGate::<F, D, R>::WIRE_INDEX_ACCUMULATOR_NEW,
|
||||||
},
|
},
|
||||||
new_index_acc_value,
|
new_index_acc_value,
|
||||||
);
|
);
|
||||||
@ -317,7 +287,7 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
|
|||||||
result.set_wire(
|
result.set_wire(
|
||||||
Wire {
|
Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: GMiMCGate::<F, R>::wire_cubing_input(r),
|
input: GMiMCGate::<F, D, R>::wire_cubing_input(r),
|
||||||
},
|
},
|
||||||
cubing_input,
|
cubing_input,
|
||||||
);
|
);
|
||||||
@ -331,7 +301,7 @@ impl<F: Field, const R: usize> SimpleGenerator<F> for GMiMCGenerator<F, R> {
|
|||||||
result.set_wire(
|
result.set_wire(
|
||||||
Wire {
|
Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: GMiMCGate::<F, R>::wire_output(i),
|
input: GMiMCGate::<F, D, R>::wire_output(i),
|
||||||
},
|
},
|
||||||
state[i],
|
state[i],
|
||||||
);
|
);
|
||||||
@ -361,7 +331,7 @@ mod tests {
|
|||||||
type F = CrandallField;
|
type F = CrandallField;
|
||||||
const R: usize = 101;
|
const R: usize = 101;
|
||||||
let constants = Arc::new([F::TWO; R]);
|
let constants = Arc::new([F::TWO; R]);
|
||||||
type Gate = GMiMCGate<F, R>;
|
type Gate = GMiMCGate<F, 4, R>;
|
||||||
let gate = Gate::with_constants(constants.clone());
|
let gate = Gate::with_constants(constants.clone());
|
||||||
|
|
||||||
let config = CircuitConfig {
|
let config = CircuitConfig {
|
||||||
@ -423,7 +393,7 @@ mod tests {
|
|||||||
type F = CrandallField;
|
type F = CrandallField;
|
||||||
const R: usize = 101;
|
const R: usize = 101;
|
||||||
let constants = Arc::new([F::TWO; R]);
|
let constants = Arc::new([F::TWO; R]);
|
||||||
type Gate = GMiMCGate<F, R>;
|
type Gate = GMiMCGate<F, 4, R>;
|
||||||
let gate = Gate::with_constants(constants);
|
let gate = Gate::with_constants(constants);
|
||||||
test_low_degree(gate)
|
test_low_degree(gate)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,239 +0,0 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
|
||||||
use crate::field::field::Field;
|
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
|
||||||
use crate::target::Target;
|
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
|
||||||
use crate::wire::Wire;
|
|
||||||
use crate::witness::PartialWitness;
|
|
||||||
|
|
||||||
/// Performs some arithmetic involved in the evaluation of GMiMC's constraint polynomials for one
|
|
||||||
/// round. In particular, this performs the following computations:
|
|
||||||
///
|
|
||||||
/// - `constraint := state_a_old + addition_buffer_old + C_r - cubing_input`
|
|
||||||
/// - `f := cubing_input^3`
|
|
||||||
/// - `addition_buffer_new := addition_buffer_old + f`
|
|
||||||
/// - `state_a_new := state_a_old - f`
|
|
||||||
///
|
|
||||||
/// Here `state_a_{old,new}` represent the old and new states of the `a`th element of the GMiMC
|
|
||||||
/// permutation. `addition_buffer_{old,new}` represents a value that is implicitly added to each
|
|
||||||
/// element; see https://affine.group/2020/02/starkware-challenge. `C_r` represents the round
|
|
||||||
/// constant for round `r`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GMiMCEvalGate<F: Field> {
|
|
||||||
_phantom: PhantomData<F>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field> GMiMCEvalGate<F> {
|
|
||||||
pub fn get() -> GateRef<F> {
|
|
||||||
GateRef::new(GMiMCEvalGate {
|
|
||||||
_phantom: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CONST_C_R: usize = 0;
|
|
||||||
|
|
||||||
pub const WIRE_CONSTRAINT: usize = 0;
|
|
||||||
pub const WIRE_STATE_A_OLD: usize = 1;
|
|
||||||
pub const WIRE_STATE_A_NEW: usize = 2;
|
|
||||||
pub const WIRE_ADDITION_BUFFER_OLD: usize = 3;
|
|
||||||
pub const WIRE_ADDITION_BUFFER_NEW: usize = 4;
|
|
||||||
pub const WIRE_CUBING_INPUT: usize = 5;
|
|
||||||
const WIRE_F: usize = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field> Gate<F> for GMiMCEvalGate<F> {
|
|
||||||
fn id(&self) -> String {
|
|
||||||
format!("{:?}", self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_unfiltered(&self, vars: EvaluationVars<F>) -> Vec<F> {
|
|
||||||
let c_r = vars.local_constants[Self::CONST_C_R];
|
|
||||||
let constraint = vars.local_wires[Self::WIRE_CONSTRAINT];
|
|
||||||
let state_a_old = vars.local_wires[Self::WIRE_STATE_A_OLD];
|
|
||||||
let state_a_new = vars.local_wires[Self::WIRE_STATE_A_NEW];
|
|
||||||
let addition_buffer_old = vars.local_wires[Self::WIRE_ADDITION_BUFFER_OLD];
|
|
||||||
let addition_buffer_new = vars.local_wires[Self::WIRE_ADDITION_BUFFER_NEW];
|
|
||||||
let cubing_input = vars.local_wires[Self::WIRE_CUBING_INPUT];
|
|
||||||
let f = vars.local_wires[Self::WIRE_F];
|
|
||||||
|
|
||||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
|
||||||
|
|
||||||
// constraint := state_a_old + addition_buffer_old + C_r - cubing_input
|
|
||||||
let computed_constraint = state_a_old + addition_buffer_old + c_r - cubing_input;
|
|
||||||
constraints.push(constraint - computed_constraint);
|
|
||||||
|
|
||||||
// f := cubing_input^3
|
|
||||||
let computed_f = cubing_input.cube();
|
|
||||||
constraints.push(f - computed_f);
|
|
||||||
|
|
||||||
// addition_buffer_new := addition_buffer_old + f
|
|
||||||
let computed_addition_buffer_new = addition_buffer_old + f;
|
|
||||||
constraints.push(addition_buffer_new - computed_addition_buffer_new);
|
|
||||||
|
|
||||||
// state_a_new := state_a_old - f
|
|
||||||
let computed_state_a_new = state_a_old - f;
|
|
||||||
constraints.push(state_a_new - computed_state_a_new);
|
|
||||||
|
|
||||||
constraints
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
|
||||||
&self,
|
|
||||||
builder: &mut CircuitBuilder<F>,
|
|
||||||
vars: EvaluationTargets,
|
|
||||||
) -> Vec<Target> {
|
|
||||||
let c_r = vars.local_constants[Self::CONST_C_R];
|
|
||||||
let constraint = vars.local_wires[Self::WIRE_CONSTRAINT];
|
|
||||||
let state_a_old = vars.local_wires[Self::WIRE_STATE_A_OLD];
|
|
||||||
let state_a_new = vars.local_wires[Self::WIRE_STATE_A_NEW];
|
|
||||||
let addition_buffer_old = vars.local_wires[Self::WIRE_ADDITION_BUFFER_OLD];
|
|
||||||
let addition_buffer_new = vars.local_wires[Self::WIRE_ADDITION_BUFFER_NEW];
|
|
||||||
let cubing_input = vars.local_wires[Self::WIRE_CUBING_INPUT];
|
|
||||||
let f = vars.local_wires[Self::WIRE_F];
|
|
||||||
|
|
||||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
|
||||||
|
|
||||||
// constraint := state_a_old + addition_buffer_old + C_r - cubing_input
|
|
||||||
let sum = builder.add_many(&[state_a_old, addition_buffer_old, c_r]);
|
|
||||||
let computed_constraint = builder.sub(sum, cubing_input);
|
|
||||||
constraints.push(builder.sub(constraint, computed_constraint));
|
|
||||||
|
|
||||||
// f := cubing_input^3
|
|
||||||
let computed_f = builder.cube(cubing_input);
|
|
||||||
constraints.push(builder.sub(f, computed_f));
|
|
||||||
|
|
||||||
// addition_buffer_new := addition_buffer_old + f
|
|
||||||
let computed_addition_buffer_new = builder.add(addition_buffer_old, f);
|
|
||||||
constraints.push(builder.sub(addition_buffer_new, computed_addition_buffer_new));
|
|
||||||
|
|
||||||
// state_a_new := state_a_old - f
|
|
||||||
let computed_state_a_new = builder.sub(state_a_old, f);
|
|
||||||
constraints.push(builder.sub(state_a_new, computed_state_a_new));
|
|
||||||
|
|
||||||
constraints
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generators(
|
|
||||||
&self,
|
|
||||||
gate_index: usize,
|
|
||||||
local_constants: &[F],
|
|
||||||
) -> Vec<Box<dyn WitnessGenerator<F>>> {
|
|
||||||
let gen = GMiMCEvalGenerator::<F> {
|
|
||||||
gate_index,
|
|
||||||
c_r: local_constants[Self::CONST_C_R],
|
|
||||||
};
|
|
||||||
vec![Box::new(gen)]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_wires(&self) -> usize {
|
|
||||||
7
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_constants(&self) -> usize {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn degree(&self) -> usize {
|
|
||||||
3
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_constraints(&self) -> usize {
|
|
||||||
4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct GMiMCEvalGenerator<F: Field> {
|
|
||||||
gate_index: usize,
|
|
||||||
c_r: F,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field> SimpleGenerator<F> for GMiMCEvalGenerator<F> {
|
|
||||||
fn dependencies(&self) -> Vec<Target> {
|
|
||||||
let gate = self.gate_index;
|
|
||||||
vec![
|
|
||||||
Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_CUBING_INPUT,
|
|
||||||
}),
|
|
||||||
Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_ADDITION_BUFFER_OLD,
|
|
||||||
}),
|
|
||||||
Target::Wire(Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_STATE_A_OLD,
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
|
||||||
let gate = self.gate_index;
|
|
||||||
let wire_constraint = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_CONSTRAINT,
|
|
||||||
};
|
|
||||||
let wire_state_a_old = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_STATE_A_OLD,
|
|
||||||
};
|
|
||||||
let wire_state_a_new = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_STATE_A_NEW,
|
|
||||||
};
|
|
||||||
let wire_addition_buffer_old = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_ADDITION_BUFFER_OLD,
|
|
||||||
};
|
|
||||||
let wire_addition_buffer_new = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_ADDITION_BUFFER_NEW,
|
|
||||||
};
|
|
||||||
let wire_cubing_input = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_CUBING_INPUT,
|
|
||||||
};
|
|
||||||
let wire_f = Wire {
|
|
||||||
gate,
|
|
||||||
input: GMiMCEvalGate::<F>::WIRE_F,
|
|
||||||
};
|
|
||||||
|
|
||||||
let addition_buffer_old = witness.get_wire(wire_addition_buffer_old);
|
|
||||||
let state_a_old = witness.get_wire(wire_state_a_old);
|
|
||||||
let cubing_input = witness.get_wire(wire_cubing_input);
|
|
||||||
|
|
||||||
// constraint := state_a_old + addition_buffer_old + C_r - cubing_input
|
|
||||||
let constraint = state_a_old + addition_buffer_old + self.c_r - cubing_input;
|
|
||||||
|
|
||||||
// f := cubing_input^3
|
|
||||||
let f = cubing_input.cube();
|
|
||||||
|
|
||||||
// addition_buffer_new := addition_buffer_old + f
|
|
||||||
let addition_buffer_new = addition_buffer_old + f;
|
|
||||||
|
|
||||||
// state_a_new := state_a_old - f
|
|
||||||
let state_a_new = state_a_old - f;
|
|
||||||
|
|
||||||
let mut witness = PartialWitness::new();
|
|
||||||
witness.set_wire(wire_constraint, constraint);
|
|
||||||
witness.set_wire(wire_f, f);
|
|
||||||
witness.set_wire(wire_state_a_new, addition_buffer_new);
|
|
||||||
witness.set_wire(wire_addition_buffer_new, state_a_new);
|
|
||||||
witness
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::field::crandall_field::CrandallField;
|
|
||||||
use crate::gates::gate_testing::test_low_degree;
|
|
||||||
use crate::gates::gmimc_eval::GMiMCEvalGate;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn low_degree() {
|
|
||||||
test_low_degree(GMiMCEvalGate::<CrandallField>::get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,10 +3,10 @@ use std::marker::PhantomData;
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::field::field::Field;
|
|
||||||
use crate::field::lagrange::interpolant;
|
use crate::field::lagrange::interpolant;
|
||||||
use crate::gadgets::polynomial::PolynomialCoeffsTarget;
|
use crate::gadgets::polynomial::PolynomialCoeffsExtExtTarget;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
||||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||||
@ -21,13 +21,19 @@ use crate::witness::PartialWitness;
|
|||||||
/// to evaluate the interpolant at. It computes the interpolant and outputs its evaluation at the
|
/// to evaluate the interpolant at. It computes the interpolant and outputs its evaluation at the
|
||||||
/// given point.
|
/// given point.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct InterpolationGate<F: Field + Extendable<D>, const D: usize> {
|
pub(crate) struct InterpolationGate<F: Extendable<D>, const D: usize>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
num_points: usize,
|
num_points: usize,
|
||||||
_phantom: PhantomData<F>,
|
_phantom: PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + Extendable<D>, const D: usize> InterpolationGate<F, D> {
|
impl<F: Extendable<D>, const D: usize> InterpolationGate<F, D>
|
||||||
pub fn new(num_points: usize) -> GateRef<F> {
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
|
pub fn new(num_points: usize) -> GateRef<F, D> {
|
||||||
let gate = Self {
|
let gate = Self {
|
||||||
num_points,
|
num_points,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
@ -93,28 +99,31 @@ impl<F: Field + Extendable<D>, const D: usize> InterpolationGate<F, D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + Extendable<D>, const D: usize> Gate<F> for InterpolationGate<F, D> {
|
impl<F: Extendable<D>, const D: usize> Gate<F, D> for InterpolationGate<F, D>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
fn id(&self) -> String {
|
fn id(&self) -> String {
|
||||||
format!("{:?}<D={}>", self, D)
|
format!("{:?}<D={}>", self, D)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unfiltered(&self, vars: EvaluationVars<F>) -> Vec<F> {
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
||||||
|
|
||||||
let coeffs = (0..self.num_points)
|
let coeffs = (0..self.num_points)
|
||||||
.map(|i| vars.get_local_ext(self.wires_coeff(i)))
|
.map(|i| vars.get_local_ext_ext(self.wires_coeff(i)))
|
||||||
.collect();
|
.collect();
|
||||||
let interpolant = PolynomialCoeffs::new(coeffs);
|
let interpolant = PolynomialCoeffs::new(coeffs);
|
||||||
|
|
||||||
for i in 0..self.num_points {
|
for i in 0..self.num_points {
|
||||||
let point = F::Extension::from_basefield(vars.local_wires[self.wire_point(i)]);
|
let point = vars.local_wires[self.wire_point(i)];
|
||||||
let value = vars.get_local_ext(self.wires_value(i));
|
let value = vars.get_local_ext_ext(self.wires_value(i));
|
||||||
let computed_value = interpolant.eval(point);
|
let computed_value = interpolant.eval(point.into());
|
||||||
constraints.extend(&(value - computed_value).to_basefield_array());
|
constraints.extend(&(value - computed_value).to_basefield_array());
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluation_point = vars.get_local_ext(self.wires_evaluation_point());
|
let evaluation_point = vars.get_local_ext_ext(self.wires_evaluation_point());
|
||||||
let evaluation_value = vars.get_local_ext(self.wires_evaluation_value());
|
let evaluation_value = vars.get_local_ext_ext(self.wires_evaluation_value());
|
||||||
let computed_evaluation_value = interpolant.eval(evaluation_point);
|
let computed_evaluation_value = interpolant.eval(evaluation_point);
|
||||||
constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array());
|
constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array());
|
||||||
|
|
||||||
@ -123,34 +132,34 @@ impl<F: Field + Extendable<D>, const D: usize> Gate<F> for InterpolationGate<F,
|
|||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
fn eval_unfiltered_recursively(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
let mut constraints = Vec::with_capacity(self.num_constraints());
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
||||||
|
|
||||||
let coeffs = (0..self.num_points)
|
let coeffs = (0..self.num_points)
|
||||||
.map(|i| vars.get_local_ext(self.wires_coeff(i)))
|
.map(|i| vars.get_local_ext_ext(self.wires_coeff(i)))
|
||||||
.collect();
|
.collect();
|
||||||
let interpolant = PolynomialCoeffsTarget(coeffs);
|
let interpolant = PolynomialCoeffsExtExtTarget(coeffs);
|
||||||
|
|
||||||
for i in 0..self.num_points {
|
for i in 0..self.num_points {
|
||||||
let point = vars.local_wires[self.wire_point(i)];
|
let point = vars.local_wires[self.wire_point(i)];
|
||||||
let value = vars.get_local_ext(self.wires_value(i));
|
let value = vars.get_local_ext_ext(self.wires_value(i));
|
||||||
let computed_value = interpolant.eval_scalar(builder, point);
|
let computed_value = interpolant.eval_scalar(builder, point);
|
||||||
constraints.extend(
|
constraints.extend(
|
||||||
&builder
|
&builder
|
||||||
.sub_extension(value, computed_value)
|
.sub_ext_ext(value, computed_value)
|
||||||
.to_target_array(),
|
.to_ext_target_array(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluation_point = vars.get_local_ext(self.wires_evaluation_point());
|
let evaluation_point = vars.get_local_ext_ext(self.wires_evaluation_point());
|
||||||
let evaluation_value = vars.get_local_ext(self.wires_evaluation_value());
|
let evaluation_value = vars.get_local_ext_ext(self.wires_evaluation_value());
|
||||||
let computed_evaluation_value = interpolant.eval(builder, evaluation_point);
|
let computed_evaluation_value = interpolant.eval(builder, evaluation_point);
|
||||||
constraints.extend(
|
constraints.extend(
|
||||||
&builder
|
&builder
|
||||||
.sub_extension(evaluation_value, computed_evaluation_value)
|
.sub_ext_ext(evaluation_value, computed_evaluation_value)
|
||||||
.to_target_array(),
|
.to_ext_target_array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
constraints
|
constraints
|
||||||
@ -190,13 +199,19 @@ impl<F: Field + Extendable<D>, const D: usize> Gate<F> for InterpolationGate<F,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InterpolationGenerator<F: Field + Extendable<D>, const D: usize> {
|
struct InterpolationGenerator<F: Extendable<D>, const D: usize>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
gate_index: usize,
|
gate_index: usize,
|
||||||
gate: InterpolationGate<F, D>,
|
gate: InterpolationGate<F, D>,
|
||||||
_phantom: PhantomData<F>,
|
_phantom: PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + Extendable<D>, const D: usize> SimpleGenerator<F> for InterpolationGenerator<F, D> {
|
impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for InterpolationGenerator<F, D>
|
||||||
|
where
|
||||||
|
F::Extension: Extendable<D>,
|
||||||
|
{
|
||||||
fn dependencies(&self) -> Vec<Target> {
|
fn dependencies(&self) -> Vec<Target> {
|
||||||
let local_target = |input| {
|
let local_target = |input| {
|
||||||
Target::Wire(Wire {
|
Target::Wire(Wire {
|
||||||
@ -293,7 +308,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn low_degree() {
|
fn low_degree() {
|
||||||
type F = CrandallField;
|
type F = CrandallField;
|
||||||
test_low_degree(InterpolationGate::<F, 2>::new(4));
|
|
||||||
test_low_degree(InterpolationGate::<F, 4>::new(4));
|
test_low_degree(InterpolationGate::<F, 4>::new(4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ pub(crate) mod arithmetic;
|
|||||||
pub mod constant;
|
pub mod constant;
|
||||||
pub(crate) mod gate;
|
pub(crate) mod gate;
|
||||||
pub mod gmimc;
|
pub mod gmimc;
|
||||||
pub(crate) mod gmimc_eval;
|
|
||||||
mod interpolation;
|
mod interpolation;
|
||||||
pub(crate) mod noop;
|
pub(crate) mod noop;
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,33 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
use crate::field::field::Field;
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::WitnessGenerator;
|
use crate::generator::WitnessGenerator;
|
||||||
use crate::target::Target;
|
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
|
|
||||||
/// A gate which takes a single constant parameter and outputs that value.
|
/// A gate which takes a single constant parameter and outputs that value.
|
||||||
pub struct NoopGate;
|
pub struct NoopGate;
|
||||||
|
|
||||||
impl NoopGate {
|
impl NoopGate {
|
||||||
pub fn get<F: Field>() -> GateRef<F> {
|
pub fn get<F: Extendable<D>, const D: usize>() -> GateRef<F, D> {
|
||||||
GateRef::new(NoopGate)
|
GateRef::new(NoopGate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Gate<F> for NoopGate {
|
impl<F: Extendable<D>, const D: usize> Gate<F, D> for NoopGate {
|
||||||
fn id(&self) -> String {
|
fn id(&self) -> String {
|
||||||
"NoopGate".into()
|
"NoopGate".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unfiltered(&self, _vars: EvaluationVars<F>) -> Vec<F> {
|
fn eval_unfiltered(&self, _vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unfiltered_recursively(
|
fn eval_unfiltered_recursively(
|
||||||
&self,
|
&self,
|
||||||
_builder: &mut CircuitBuilder<F>,
|
_builder: &mut CircuitBuilder<F, D>,
|
||||||
_vars: EvaluationTargets,
|
_vars: EvaluationTargets<D>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +64,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn low_degree() {
|
fn low_degree() {
|
||||||
test_low_degree(NoopGate::get::<CrandallField>())
|
test_low_degree(NoopGate::get::<CrandallField, 4>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
//! Concrete instantiation of a hash function.
|
//! Concrete instantiation of a hash function.
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gmimc::gmimc_permute_array;
|
use crate::gmimc::gmimc_permute_array;
|
||||||
use crate::proof::{Hash, HashTarget};
|
use crate::proof::{Hash, HashTarget};
|
||||||
@ -132,7 +133,7 @@ pub fn hash_or_noop<F: Field>(inputs: Vec<F>) -> Hash<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
pub fn hash_or_noop(&mut self, inputs: Vec<Target>) -> HashTarget {
|
pub fn hash_or_noop(&mut self, inputs: Vec<Target>) -> HashTarget {
|
||||||
let zero = self.zero();
|
let zero = self.zero();
|
||||||
if inputs.len() <= 4 {
|
if inputs.len() <= 4 {
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
|
use anyhow::{ensure, Result};
|
||||||
|
|
||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gmimc::GMiMCGate;
|
use crate::gates::gmimc::GMiMCGate;
|
||||||
use crate::hash::GMIMC_ROUNDS;
|
use crate::hash::GMIMC_ROUNDS;
|
||||||
@ -6,7 +9,6 @@ use crate::hash::{compress, hash_or_noop};
|
|||||||
use crate::proof::{Hash, HashTarget};
|
use crate::proof::{Hash, HashTarget};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
use anyhow::{ensure, Result};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MerkleProof<F: Field> {
|
pub struct MerkleProof<F: Field> {
|
||||||
@ -52,7 +54,7 @@ pub(crate) fn verify_merkle_proof<F: Field>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> CircuitBuilder<F> {
|
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
|
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
|
||||||
/// given root.
|
/// given root.
|
||||||
pub(crate) fn verify_merkle_proof(
|
pub(crate) fn verify_merkle_proof(
|
||||||
@ -71,23 +73,23 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
|
|
||||||
for (bit, sibling) in purported_index_bits.into_iter().zip(proof.siblings) {
|
for (bit, sibling) in purported_index_bits.into_iter().zip(proof.siblings) {
|
||||||
let gate = self
|
let gate = self
|
||||||
.add_gate_no_constants(GMiMCGate::<F, GMIMC_ROUNDS>::with_automatic_constants());
|
.add_gate_no_constants(GMiMCGate::<F, D, GMIMC_ROUNDS>::with_automatic_constants());
|
||||||
|
|
||||||
let swap_wire = GMiMCGate::<F, GMIMC_ROUNDS>::WIRE_SWAP;
|
let swap_wire = GMiMCGate::<F, D, GMIMC_ROUNDS>::WIRE_SWAP;
|
||||||
let swap_wire = Target::Wire(Wire {
|
let swap_wire = Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: swap_wire,
|
input: swap_wire,
|
||||||
});
|
});
|
||||||
self.generate_copy(bit, swap_wire);
|
self.generate_copy(bit, swap_wire);
|
||||||
|
|
||||||
let old_acc_wire = GMiMCGate::<F, GMIMC_ROUNDS>::WIRE_INDEX_ACCUMULATOR_OLD;
|
let old_acc_wire = GMiMCGate::<F, D, GMIMC_ROUNDS>::WIRE_INDEX_ACCUMULATOR_OLD;
|
||||||
let old_acc_wire = Target::Wire(Wire {
|
let old_acc_wire = Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: old_acc_wire,
|
input: old_acc_wire,
|
||||||
});
|
});
|
||||||
self.route(acc_leaf_index, old_acc_wire);
|
self.route(acc_leaf_index, old_acc_wire);
|
||||||
|
|
||||||
let new_acc_wire = GMiMCGate::<F, GMIMC_ROUNDS>::WIRE_INDEX_ACCUMULATOR_NEW;
|
let new_acc_wire = GMiMCGate::<F, D, GMIMC_ROUNDS>::WIRE_INDEX_ACCUMULATOR_NEW;
|
||||||
let new_acc_wire = Target::Wire(Wire {
|
let new_acc_wire = Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: new_acc_wire,
|
input: new_acc_wire,
|
||||||
@ -98,7 +100,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
.map(|i| {
|
.map(|i| {
|
||||||
Target::Wire(Wire {
|
Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_input(i),
|
input: GMiMCGate::<F, D, GMIMC_ROUNDS>::wire_input(i),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -114,7 +116,7 @@ impl<F: Field> CircuitBuilder<F> {
|
|||||||
.map(|i| {
|
.map(|i| {
|
||||||
Target::Wire(Wire {
|
Target::Wire(Wire {
|
||||||
gate,
|
gate,
|
||||||
input: GMiMCGate::<F, GMIMC_ROUNDS>::wire_output(i),
|
input: GMiMCGate::<F, D, GMIMC_ROUNDS>::wire_output(i),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|||||||
@ -160,7 +160,9 @@ pub(crate) struct RecursiveChallenger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RecursiveChallenger {
|
impl RecursiveChallenger {
|
||||||
pub(crate) fn new<F: Field>(builder: &mut CircuitBuilder<F>) -> Self {
|
pub(crate) fn new<F: Extendable<D>, const D: usize>(
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
) -> Self {
|
||||||
let zero = builder.zero();
|
let zero = builder.zero();
|
||||||
RecursiveChallenger {
|
RecursiveChallenger {
|
||||||
sponge_state: [zero; SPONGE_WIDTH],
|
sponge_state: [zero; SPONGE_WIDTH],
|
||||||
@ -186,7 +188,10 @@ impl RecursiveChallenger {
|
|||||||
self.observe_elements(&hash.elements)
|
self.observe_elements(&hash.elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_challenge<F: Field>(&mut self, builder: &mut CircuitBuilder<F>) -> Target {
|
pub(crate) fn get_challenge<F: Extendable<D>, const D: usize>(
|
||||||
|
&mut self,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
) -> Target {
|
||||||
self.absorb_buffered_inputs(builder);
|
self.absorb_buffered_inputs(builder);
|
||||||
|
|
||||||
if self.output_buffer.is_empty() {
|
if self.output_buffer.is_empty() {
|
||||||
@ -200,16 +205,16 @@ impl RecursiveChallenger {
|
|||||||
.expect("Output buffer should be non-empty")
|
.expect("Output buffer should be non-empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_2_challenges<F: Field>(
|
pub(crate) fn get_2_challenges<F: Extendable<D>, const D: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
) -> (Target, Target) {
|
) -> (Target, Target) {
|
||||||
(self.get_challenge(builder), self.get_challenge(builder))
|
(self.get_challenge(builder), self.get_challenge(builder))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_3_challenges<F: Field>(
|
pub(crate) fn get_3_challenges<F: Extendable<D>, const D: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
) -> (Target, Target, Target) {
|
) -> (Target, Target, Target) {
|
||||||
(
|
(
|
||||||
self.get_challenge(builder),
|
self.get_challenge(builder),
|
||||||
@ -218,16 +223,19 @@ impl RecursiveChallenger {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_n_challenges<F: Field>(
|
pub(crate) fn get_n_challenges<F: Extendable<D>, const D: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
n: usize,
|
n: usize,
|
||||||
) -> Vec<Target> {
|
) -> Vec<Target> {
|
||||||
(0..n).map(|_| self.get_challenge(builder)).collect()
|
(0..n).map(|_| self.get_challenge(builder)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Absorb any buffered inputs. After calling this, the input buffer will be empty.
|
/// Absorb any buffered inputs. After calling this, the input buffer will be empty.
|
||||||
fn absorb_buffered_inputs<F: Field>(&mut self, builder: &mut CircuitBuilder<F>) {
|
fn absorb_buffered_inputs<F: Extendable<D>, const D: usize>(
|
||||||
|
&mut self,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
) {
|
||||||
if self.input_buffer.is_empty() {
|
if self.input_buffer.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -308,7 +316,7 @@ mod tests {
|
|||||||
num_routed_wires: 27,
|
num_routed_wires: 27,
|
||||||
..CircuitConfig::default()
|
..CircuitConfig::default()
|
||||||
};
|
};
|
||||||
let mut builder = CircuitBuilder::<F>::new(config);
|
let mut builder = CircuitBuilder::<F, 4>::new(config);
|
||||||
let mut recursive_challenger = RecursiveChallenger::new(&mut builder);
|
let mut recursive_challenger = RecursiveChallenger::new(&mut builder);
|
||||||
let mut recursive_outputs_per_round: Vec<Vec<Target>> = Vec::new();
|
let mut recursive_outputs_per_round: Vec<Vec<Target>> = Vec::new();
|
||||||
for (r, inputs) in inputs_per_round.iter().enumerate() {
|
for (r, inputs) in inputs_per_round.iter().enumerate() {
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::GateRef;
|
use crate::gates::gate::GateRef;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
|
||||||
|
|
||||||
/// Evaluates all gate constraints.
|
/// Evaluates all gate constraints.
|
||||||
///
|
///
|
||||||
/// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not
|
/// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not
|
||||||
/// strictly necessary, but it helps performance by ensuring that we allocate a vector with exactly
|
/// strictly necessary, but it helps performance by ensuring that we allocate a vector with exactly
|
||||||
/// the capacity that we need.
|
/// the capacity that we need.
|
||||||
pub fn evaluate_gate_constraints<F: Field>(
|
pub fn evaluate_gate_constraints<F: Extendable<D>, const D: usize>(
|
||||||
gates: &[GateRef<F>],
|
gates: &[GateRef<F, D>],
|
||||||
num_gate_constraints: usize,
|
num_gate_constraints: usize,
|
||||||
vars: EvaluationVars<F>,
|
vars: EvaluationVars<F, D>,
|
||||||
) -> Vec<F> {
|
) -> Vec<F::Extension> {
|
||||||
let mut constraints = vec![F::ZERO; num_gate_constraints];
|
let mut constraints = vec![F::Extension::ZERO; num_gate_constraints];
|
||||||
for gate in gates {
|
for gate in gates {
|
||||||
let gate_constraints = gate.0.eval_filtered(vars);
|
let gate_constraints = gate.0.eval_filtered(vars);
|
||||||
for (i, c) in gate_constraints.into_iter().enumerate() {
|
for (i, c) in gate_constraints.into_iter().enumerate() {
|
||||||
@ -28,17 +30,36 @@ pub fn evaluate_gate_constraints<F: Field>(
|
|||||||
constraints
|
constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluate_gate_constraints_recursively<F: Field>(
|
pub fn evaluate_gate_constraints_base<F: Extendable<D>, const D: usize>(
|
||||||
builder: &mut CircuitBuilder<F>,
|
gates: &[GateRef<F, D>],
|
||||||
gates: &[GateRef<F>],
|
|
||||||
num_gate_constraints: usize,
|
num_gate_constraints: usize,
|
||||||
vars: EvaluationTargets,
|
vars: EvaluationVarsBase<F>,
|
||||||
) -> Vec<Target> {
|
) -> Vec<F> {
|
||||||
let mut constraints = vec![builder.zero(); num_gate_constraints];
|
let mut constraints = vec![F::ZERO; num_gate_constraints];
|
||||||
|
for gate in gates {
|
||||||
|
let gate_constraints = gate.0.eval_filtered_base(vars);
|
||||||
|
for (i, c) in gate_constraints.into_iter().enumerate() {
|
||||||
|
debug_assert!(
|
||||||
|
i < num_gate_constraints,
|
||||||
|
"num_constraints() gave too low of a number"
|
||||||
|
);
|
||||||
|
constraints[i] += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constraints
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evaluate_gate_constraints_recursively<F: Extendable<D>, const D: usize>(
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
gates: &[GateRef<F, D>],
|
||||||
|
num_gate_constraints: usize,
|
||||||
|
vars: EvaluationTargets<D>,
|
||||||
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
|
let mut constraints = vec![builder.zero_extension(); num_gate_constraints];
|
||||||
for gate in gates {
|
for gate in gates {
|
||||||
let gate_constraints = gate.0.eval_filtered_recursively(builder, vars);
|
let gate_constraints = gate.0.eval_filtered_recursively(builder, vars);
|
||||||
for (i, c) in gate_constraints.into_iter().enumerate() {
|
for (i, c) in gate_constraints.into_iter().enumerate() {
|
||||||
constraints[i] = builder.add(constraints[i], c);
|
constraints[i] = builder.add_extension(constraints[i], c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constraints
|
constraints
|
||||||
@ -80,8 +101,8 @@ pub(crate) fn reduce_with_powers<F: Field>(terms: &[F], alpha: F) -> F {
|
|||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reduce_with_powers_recursive<F: Field>(
|
pub(crate) fn reduce_with_powers_recursive<F: Extendable<D>, const D: usize>(
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
terms: Vec<Target>,
|
terms: Vec<Target>,
|
||||||
alpha: Target,
|
alpha: Target,
|
||||||
) -> Target {
|
) -> Target {
|
||||||
|
|||||||
@ -359,8 +359,6 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::field::crandall_field::CrandallField;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn gen_random_test_case<F: Field + Extendable<D>, const D: usize>(
|
fn gen_random_test_case<F: Field + Extendable<D>, const D: usize>(
|
||||||
|
|||||||
@ -9,22 +9,22 @@ use crate::field::fft::ifft;
|
|||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::generator::generate_partial_witness;
|
use crate::generator::generate_partial_witness;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::plonk_common::{eval_l_1, evaluate_gate_constraints, reduce_with_powers_multi};
|
use crate::plonk_common::{eval_l_1, evaluate_gate_constraints_base, reduce_with_powers_multi};
|
||||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
use crate::proof::Proof;
|
use crate::proof::Proof;
|
||||||
use crate::timed;
|
use crate::timed;
|
||||||
use crate::util::transpose;
|
use crate::util::transpose;
|
||||||
use crate::vars::EvaluationVars;
|
use crate::vars::EvaluationVarsBase;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
/// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments.
|
/// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments.
|
||||||
pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true];
|
pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true];
|
||||||
|
|
||||||
pub(crate) fn prove<F: Field + Extendable<D>, const D: usize>(
|
pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
||||||
prover_data: &ProverOnlyCircuitData<F>,
|
prover_data: &ProverOnlyCircuitData<F>,
|
||||||
common_data: &CommonCircuitData<F>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
inputs: PartialWitness<F>,
|
inputs: PartialWitness<F>,
|
||||||
) -> Proof<F, D> {
|
) -> Proof<F, D> {
|
||||||
let fri_config = &common_data.config.fri_config;
|
let fri_config = &common_data.config.fri_config;
|
||||||
@ -113,7 +113,7 @@ pub(crate) fn prove<F: Field + Extendable<D>, const D: usize>(
|
|||||||
|
|
||||||
challenger.observe_hash("ient_polys_commitment.merkle_tree.root);
|
challenger.observe_hash("ient_polys_commitment.merkle_tree.root);
|
||||||
|
|
||||||
let zetas = challenger.get_n_extension_challenges(config.num_challenges);
|
let zeta = challenger.get_extension_challenge();
|
||||||
|
|
||||||
let (opening_proof, openings) = timed!(
|
let (opening_proof, openings) = timed!(
|
||||||
ListPolynomialCommitment::batch_open_plonk(
|
ListPolynomialCommitment::batch_open_plonk(
|
||||||
@ -124,7 +124,7 @@ pub(crate) fn prove<F: Field + Extendable<D>, const D: usize>(
|
|||||||
&plonk_zs_commitment,
|
&plonk_zs_commitment,
|
||||||
"ient_polys_commitment,
|
"ient_polys_commitment,
|
||||||
],
|
],
|
||||||
&zetas,
|
&[zeta],
|
||||||
&mut challenger,
|
&mut challenger,
|
||||||
&common_data.config.fri_config
|
&common_data.config.fri_config
|
||||||
),
|
),
|
||||||
@ -145,19 +145,23 @@ pub(crate) fn prove<F: Field + Extendable<D>, const D: usize>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<PolynomialCoeffs<F>> {
|
fn compute_zs<F: Extendable<D>, const D: usize>(
|
||||||
|
common_data: &CommonCircuitData<F, D>,
|
||||||
|
) -> Vec<PolynomialCoeffs<F>> {
|
||||||
(0..common_data.config.num_challenges)
|
(0..common_data.config.num_challenges)
|
||||||
.map(|i| compute_z(common_data, i))
|
.map(|i| compute_z(common_data, i))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, _i: usize) -> PolynomialCoeffs<F> {
|
fn compute_z<F: Extendable<D>, const D: usize>(
|
||||||
|
common_data: &CommonCircuitData<F, D>,
|
||||||
|
_i: usize,
|
||||||
|
) -> PolynomialCoeffs<F> {
|
||||||
PolynomialCoeffs::zero(common_data.degree()) // TODO
|
PolynomialCoeffs::zero(common_data.degree()) // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Parallelize.
|
fn compute_vanishing_polys<F: Extendable<D>, const D: usize>(
|
||||||
fn compute_vanishing_polys<F: Field>(
|
common_data: &CommonCircuitData<F, D>,
|
||||||
common_data: &CommonCircuitData<F>,
|
|
||||||
prover_data: &ProverOnlyCircuitData<F>,
|
prover_data: &ProverOnlyCircuitData<F>,
|
||||||
wires_commitment: &ListPolynomialCommitment<F>,
|
wires_commitment: &ListPolynomialCommitment<F>,
|
||||||
plonk_zs_commitment: &ListPolynomialCommitment<F>,
|
plonk_zs_commitment: &ListPolynomialCommitment<F>,
|
||||||
@ -184,7 +188,7 @@ fn compute_vanishing_polys<F: Field>(
|
|||||||
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
|
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
|
||||||
debug_assert_eq!(local_plonk_zs.len(), num_challenges);
|
debug_assert_eq!(local_plonk_zs.len(), num_challenges);
|
||||||
|
|
||||||
let vars = EvaluationVars {
|
let vars = EvaluationVarsBase {
|
||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
};
|
};
|
||||||
@ -211,10 +215,10 @@ fn compute_vanishing_polys<F: Field>(
|
|||||||
/// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random
|
/// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random
|
||||||
/// linear combination of gate constraints, plus some other terms relating to the permutation
|
/// linear combination of gate constraints, plus some other terms relating to the permutation
|
||||||
/// argument. All such terms should vanish on `H`.
|
/// argument. All such terms should vanish on `H`.
|
||||||
fn compute_vanishing_poly_entry<F: Field>(
|
fn compute_vanishing_poly_entry<F: Extendable<D>, const D: usize>(
|
||||||
common_data: &CommonCircuitData<F>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
x: F,
|
x: F,
|
||||||
vars: EvaluationVars<F>,
|
vars: EvaluationVarsBase<F>,
|
||||||
local_plonk_zs: &[F],
|
local_plonk_zs: &[F],
|
||||||
next_plonk_zs: &[F],
|
next_plonk_zs: &[F],
|
||||||
s_sigmas: &[F],
|
s_sigmas: &[F],
|
||||||
@ -223,7 +227,7 @@ fn compute_vanishing_poly_entry<F: Field>(
|
|||||||
alphas: &[F],
|
alphas: &[F],
|
||||||
) -> Vec<F> {
|
) -> Vec<F> {
|
||||||
let constraint_terms =
|
let constraint_terms =
|
||||||
evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars);
|
evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars);
|
||||||
|
|
||||||
// The L_1(x) (Z(x) - 1) vanishing terms.
|
// The L_1(x) (Z(x) - 1) vanishing terms.
|
||||||
let mut vanishing_z_1_terms = Vec::new();
|
let mut vanishing_z_1_terms = Vec::new();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::circuit_builder::CircuitBuilder;
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
use crate::circuit_data::{CircuitConfig, VerifierCircuitTarget};
|
use crate::circuit_data::{CircuitConfig, VerifierCircuitTarget};
|
||||||
use crate::field::field::Field;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::gates::gate::GateRef;
|
use crate::gates::gate::GateRef;
|
||||||
use crate::proof::ProofTarget;
|
use crate::proof::ProofTarget;
|
||||||
|
|
||||||
@ -8,11 +8,11 @@ const MIN_WIRES: usize = 120; // TODO: Double check.
|
|||||||
const MIN_ROUTED_WIRES: usize = 8; // TODO: Double check.
|
const MIN_ROUTED_WIRES: usize = 8; // TODO: Double check.
|
||||||
|
|
||||||
/// Recursively verifies an inner proof.
|
/// Recursively verifies an inner proof.
|
||||||
pub fn add_recursive_verifier<F: Field>(
|
pub fn add_recursive_verifier<F: Extendable<D>, const D: usize>(
|
||||||
builder: &mut CircuitBuilder<F>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
inner_config: CircuitConfig,
|
inner_config: CircuitConfig,
|
||||||
inner_circuit: VerifierCircuitTarget,
|
inner_circuit: VerifierCircuitTarget,
|
||||||
inner_gates: Vec<GateRef<F>>,
|
inner_gates: Vec<GateRef<F, D>>,
|
||||||
inner_proof: ProofTarget,
|
inner_proof: ProofTarget,
|
||||||
) {
|
) {
|
||||||
assert!(builder.config.num_wires >= MIN_WIRES);
|
assert!(builder.config.num_wires >= MIN_WIRES);
|
||||||
|
|||||||
34
src/vars.rs
34
src/vars.rs
@ -1,38 +1,46 @@
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::field::extension_field::target::ExtensionTarget;
|
use crate::field::extension_field::target::{ExtensionExtensionTarget, ExtensionTarget};
|
||||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::target::Target;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct EvaluationVars<'a, F: Field> {
|
pub struct EvaluationVars<'a, F: Extendable<D>, const D: usize> {
|
||||||
|
pub(crate) local_constants: &'a [F::Extension],
|
||||||
|
pub(crate) local_wires: &'a [F::Extension],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct EvaluationVarsBase<'a, F: Field> {
|
||||||
pub(crate) local_constants: &'a [F],
|
pub(crate) local_constants: &'a [F],
|
||||||
pub(crate) local_wires: &'a [F],
|
pub(crate) local_wires: &'a [F],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, F: Field> EvaluationVars<'a, F> {
|
impl<'a, F: Extendable<D>, const D: usize> EvaluationVars<'a, F, D> {
|
||||||
pub fn get_local_ext<const D: usize>(&self, wire_range: Range<usize>) -> F::Extension
|
pub fn get_local_ext_ext(
|
||||||
|
&self,
|
||||||
|
wire_range: Range<usize>,
|
||||||
|
) -> <<F as Extendable<D>>::Extension as Extendable<D>>::Extension
|
||||||
where
|
where
|
||||||
F: Extendable<D>,
|
F::Extension: Extendable<D>,
|
||||||
{
|
{
|
||||||
debug_assert_eq!(wire_range.len(), D);
|
debug_assert_eq!(wire_range.len(), D);
|
||||||
let arr = self.local_wires[wire_range].try_into().unwrap();
|
let arr = self.local_wires[wire_range].try_into().unwrap();
|
||||||
F::Extension::from_basefield_array(arr)
|
<<F as Extendable<D>>::Extension as Extendable<D>>::Extension::from_basefield_array(arr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct EvaluationTargets<'a> {
|
pub struct EvaluationTargets<'a, const D: usize> {
|
||||||
pub(crate) local_constants: &'a [Target],
|
pub(crate) local_constants: &'a [ExtensionTarget<D>],
|
||||||
pub(crate) local_wires: &'a [Target],
|
pub(crate) local_wires: &'a [ExtensionTarget<D>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EvaluationTargets<'a> {
|
impl<'a, const D: usize> EvaluationTargets<'a, D> {
|
||||||
pub fn get_local_ext<const D: usize>(&self, wire_range: Range<usize>) -> ExtensionTarget<D> {
|
pub fn get_local_ext_ext(&self, wire_range: Range<usize>) -> ExtensionExtensionTarget<D> {
|
||||||
debug_assert_eq!(wire_range.len(), D);
|
debug_assert_eq!(wire_range.len(), D);
|
||||||
let arr = self.local_wires[wire_range].try_into().unwrap();
|
let arr = self.local_wires[wire_range].try_into().unwrap();
|
||||||
ExtensionTarget(arr)
|
ExtensionExtensionTarget(arr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,13 @@ use anyhow::Result;
|
|||||||
|
|
||||||
use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::proof::Proof;
|
use crate::proof::Proof;
|
||||||
|
|
||||||
pub(crate) fn verify<F: Field + Extendable<D>, const D: usize>(
|
pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
||||||
proof: Proof<F, D>,
|
proof: Proof<F, D>,
|
||||||
verifier_data: &VerifierOnlyCircuitData<F>,
|
verifier_data: &VerifierOnlyCircuitData<F>,
|
||||||
common_data: &CommonCircuitData<F>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = &common_data.config;
|
let config = &common_data.config;
|
||||||
let fri_config = &config.fri_config;
|
let fri_config = &config.fri_config;
|
||||||
@ -28,7 +27,7 @@ pub(crate) fn verify<F: Field + Extendable<D>, const D: usize>(
|
|||||||
let alphas = challenger.get_n_challenges(num_challenges);
|
let alphas = challenger.get_n_challenges(num_challenges);
|
||||||
|
|
||||||
challenger.observe_hash(&proof.quotient_polys_root);
|
challenger.observe_hash(&proof.quotient_polys_root);
|
||||||
let zetas = challenger.get_n_extension_challenges(config.num_challenges);
|
let zeta = challenger.get_extension_challenge();
|
||||||
|
|
||||||
// TODO: Compute PI(zeta), Z_H(zeta), etc. and check the identity at zeta.
|
// TODO: Compute PI(zeta), Z_H(zeta), etc. and check the identity at zeta.
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ pub(crate) fn verify<F: Field + Extendable<D>, const D: usize>(
|
|||||||
];
|
];
|
||||||
|
|
||||||
proof.opening_proof.verify(
|
proof.opening_proof.verify(
|
||||||
&zetas,
|
&[zeta],
|
||||||
evaluations,
|
evaluations,
|
||||||
merkle_roots,
|
merkle_roots,
|
||||||
&mut challenger,
|
&mut challenger,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user