Skip to content

Commit

Permalink
MSM/Serialization: build lookup witnesses
Browse files Browse the repository at this point in the history
  • Loading branch information
dannywillems committed Mar 12, 2024
1 parent 1e1ba14 commit ef67192
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 8 deletions.
127 changes: 121 additions & 6 deletions msm/src/serialization/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{mvlookup::LookupTableID, MVLookup};
use ark_ff::Field;

use crate::mvlookup::LookupTableID;

/// The number of intermediate limbs of 4 bits required for the circuit
pub const N_INTERMEDIATE_LIMBS: usize = 20;

Expand All @@ -10,6 +9,7 @@ pub mod constraints;
pub mod interpreter;
pub mod witness;

#[derive(Clone, Copy, Debug)]
pub enum LookupTable {
RangeCheck15,
RangeCheck4,
Expand All @@ -24,15 +24,19 @@ impl LookupTableID for LookupTable {
}
}

pub type Lookup<F> = MVLookup<F, LookupTable>;

#[cfg(test)]
mod tests {
use kimchi::circuits::domains::EvaluationDomains;
use poly_commitment::pairing_proof::PairingSRS;
use rand::Rng as _;

use super::{Lookup, LookupTable};

use crate::{
columns::Column,
lookups::LookupTableIDs,
mvlookup::MVLookupWitness,
precomputed_srs::get_bn254_srs,
proof::ProofInputs,
prover::prove,
Expand All @@ -44,6 +48,40 @@ mod tests {
BaseSponge, Fp, OpeningProof, ScalarSponge, BN254, N_LIMBS,
};

use ark_ff::{FftField, Field, PrimeField};

impl LookupTable {
fn into_lookup_vector<F: FftField + PrimeField + Field>(
self,
domain: EvaluationDomains<F>,
) -> Vec<Lookup<F>> {
assert!(domain.d1.size >= (1 << 15));
match self {
Self::RangeCheck15 => (0..(1 << 15))
.map(|i| Lookup {
table_id: LookupTable::RangeCheck15,
numerator: -F::one(),
value: vec![F::from(i as u64)],
})
.collect::<Vec<Lookup<F>>>(),
Self::RangeCheck4 => (0..(1 << 15))
.map(|i| {
if i < (1 << 4) {
F::from(i as u64)
} else {
F::zero()
}
})
.map(|x| Lookup {
table_id: LookupTable::RangeCheck4,
numerator: -F::one(),
value: vec![x],
})
.collect::<Vec<Lookup<F>>>(),
}
}
}

#[test]
fn test_completeness() {
let mut rng = o1_utils::tests::make_test_rng();
Expand Down Expand Up @@ -77,7 +115,12 @@ mod tests {
}

let mut constraints = vec![];
for limbs in field_elements {

let mut rangecheck15: [Vec<Lookup<Fp>>; N_LIMBS] = std::array::from_fn(|_| vec![]);
let mut rangecheck4: [Vec<Lookup<Fp>>; N_INTERMEDIATE_LIMBS] =
std::array::from_fn(|_| vec![]);

for (i, limbs) in field_elements.into_iter().enumerate() {
let mut constraint_env = constraints::Env::<Fp>::create();
// Witness
deserialize_field_element(&mut witness_env, limbs);
Expand All @@ -102,11 +145,83 @@ mod tests {
constraints.push(cst.clone())
}
}

for (j, lookup) in witness_env.rangecheck4_lookups.iter().enumerate() {
rangecheck4[j].push(lookup.clone())
}

for (j, lookup) in witness_env.rangecheck15_lookups.iter().enumerate() {
rangecheck15[j].push(lookup.clone())
}

witness_env.add_rangecheck4_table_value(i);

witness_env.reset()
}

let rangecheck15_m = witness_env.get_rangecheck15_normalized_multipliticies(domain);
let rangecheck15_t = LookupTable::RangeCheck15
.into_lookup_vector(domain)
.into_iter()
.enumerate()
.map(
|(
i,
Lookup {
table_id,
numerator,
value,
},
)| {
Lookup {
table_id,
numerator: numerator * rangecheck15_m[i],
value,
}
},
);

let rangecheck4_m = witness_env.get_rangecheck4_normalized_multipliticies(domain);
let rangecheck4_t = LookupTable::RangeCheck4
.into_lookup_vector(domain)
.into_iter()
.enumerate()
.map(
|(
i,
Lookup {
table_id,
numerator,
value,
},
)| {
Lookup {
table_id,
numerator: numerator * rangecheck4_m[i],
value,
}
},
);

let lookup_witness_rangecheck4: MVLookupWitness<Fp, LookupTable> = {
MVLookupWitness {
f: rangecheck4.to_vec(),
t: rangecheck4_t.collect(),
m: rangecheck4_m,
}
};

let lookup_witness_rangecheck15: MVLookupWitness<Fp, LookupTable> = {
MVLookupWitness {
f: rangecheck15.to_vec(),
t: rangecheck15_t.collect(),
m: rangecheck15_m,
}
};

let proof_inputs = ProofInputs {
evaluations: *witness,
mvlookups: vec![],
mvlookups: vec![lookup_witness_rangecheck15, lookup_witness_rangecheck4],
public_input_size: 0,
};

Expand All @@ -118,7 +233,7 @@ mod tests {
Column,
_,
SERIALIZATION_N_COLUMNS,
LookupTableIDs,
LookupTable,
>(domain, &srs, &constraints, proof_inputs, &mut rng)
.unwrap();

Expand Down
74 changes: 72 additions & 2 deletions msm/src/serialization/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use o1_utils::FieldHelpers;

use crate::columns::Column;
use crate::serialization::interpreter::InterpreterEnv;
use crate::serialization::{Lookup, LookupTable};
use crate::N_LIMBS;
use kimchi::circuits::domains::EvaluationDomains;
use std::iter;

use super::N_INTERMEDIATE_LIMBS;

Expand All @@ -17,9 +20,26 @@ pub struct Env<Fp> {
/// field Kimchi gate
pub intermediate_limbs: [Fp; N_INTERMEDIATE_LIMBS],

/// Keep track of the RangeCheck4 lookup multiplicities
// Boxing to avoid stack overflow
pub lookup_multiplicities_rangecheck4: Box<[Fp; 1 << 4]>,

/// Keep track of the RangeCheck4 table multiplicities.
/// The value `0` is used as a (repeated) dummy value.
// Boxing to avoid stack overflow
pub lookup_t_multiplicities_rangecheck4: Box<[Fp; 1 << 4]>,

/// Keep track of the RangeCheck15 lookup multiplicities
/// No t multiplicities as we do suppose we have a domain of
/// size `1 << 15`
// Boxing to avoid stack overflow
pub lookup_multiplicities_rangecheck15: Box<[Fp; 1 << 15]>,

/// Keep track of the rangecheck 4 lookups for each row.
pub rangecheck4_lookups: Vec<Lookup<Fp>>,

/// Keep track of the rangecheck 15 lookups for each row.
pub rangecheck15_lookups: Vec<Lookup<Fp>>,
}

impl<Fp: PrimeField> InterpreterEnv<Fp> for Env<Fp> {
Expand Down Expand Up @@ -48,21 +68,29 @@ impl<Fp: PrimeField> InterpreterEnv<Fp> for Env<Fp> {
}

fn range_check15(&mut self, value: &Self::Variable) {
// FIXME: this is not the full intended implementation
let value_biguint = value.to_biguint();
assert!(value_biguint < BigUint::from(2u128.pow(15)));
// Adding multiplicities
let value_usize: usize = value_biguint.clone().try_into().unwrap();
self.lookup_multiplicities_rangecheck15[value_usize] += Fp::one();
self.rangecheck15_lookups.push(Lookup {
table_id: LookupTable::RangeCheck15,
numerator: Fp::one(),
value: vec![*value],
})
}

fn range_check4(&mut self, value: &Self::Variable) {
// FIXME: this is not the full intended implementation
let value_biguint = value.to_biguint();
assert!(value_biguint < BigUint::from(2u128.pow(4)));
// Adding multiplicities
let value_usize: usize = value_biguint.clone().try_into().unwrap();
self.lookup_multiplicities_rangecheck4[value_usize] += Fp::one();
self.rangecheck4_lookups.push(Lookup {
table_id: LookupTable::RangeCheck4,
numerator: Fp::one(),
value: vec![*value],
})
}

fn copy(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable {
Expand Down Expand Up @@ -112,6 +140,43 @@ impl<Fp: PrimeField> Env<Fp> {
}
}
}

pub fn add_rangecheck4_table_value(&mut self, i: usize) {
if i < (1 << 4) {
self.lookup_t_multiplicities_rangecheck4[i] += Fp::one();
} else {
self.lookup_t_multiplicities_rangecheck4[0] += Fp::one();
}
}

pub fn reset(&mut self) {
self.rangecheck15_lookups = vec![];
self.rangecheck4_lookups = vec![];
}

pub fn get_rangecheck4_normalized_multipliticies(
&self,
domain: EvaluationDomains<Fp>,
) -> Vec<Fp> {
let mut m = vec![Fp::zero(); 1 << 4];
self.lookup_multiplicities_rangecheck4
.into_iter()
.zip(self.lookup_t_multiplicities_rangecheck4.iter())
.enumerate()
.for_each(|(i, (m_f, m_t))| m[i] = m_f / m_t);
let repeated_dummy_value: Vec<Fp> = iter::repeat(m[0])
.take((domain.d1.size - (1 << 4)) as usize)
.collect();
m.extend(repeated_dummy_value);
m
}

pub fn get_rangecheck15_normalized_multipliticies(
&self,
_domain: EvaluationDomains<Fp>,
) -> Vec<Fp> {
self.lookup_multiplicities_rangecheck15.to_vec()
}
}

impl<Fp: PrimeField> Env<Fp> {
Expand All @@ -120,8 +185,13 @@ impl<Fp: PrimeField> Env<Fp> {
current_kimchi_limbs: [Fp::zero(); 3],
msm_limbs: [Fp::zero(); N_LIMBS],
intermediate_limbs: [Fp::zero(); N_INTERMEDIATE_LIMBS],

lookup_multiplicities_rangecheck4: Box::new([Fp::zero(); 1 << 4]),
lookup_t_multiplicities_rangecheck4: Box::new([Fp::zero(); 1 << 4]),

lookup_multiplicities_rangecheck15: Box::new([Fp::zero(); 1 << 15]),
rangecheck4_lookups: vec![],
rangecheck15_lookups: vec![],
}
}
}
Expand Down

0 comments on commit ef67192

Please sign in to comment.