use crate::logup::{Logup, LogupWitness, LookupTableID};
use ark_ff::{FftField, PrimeField};
use kimchi::circuits::domains::EvaluationDomains;
use rand::{seq::SliceRandom, thread_rng, Rng};
use std::{cmp::Ord, iter};
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum DummyLookupTable {
DummyLookupTable,
}
impl LookupTableID for DummyLookupTable {
fn to_u32(&self) -> u32 {
1
}
fn from_u32(id: u32) -> Self {
match id {
1 => DummyLookupTable::DummyLookupTable,
_ => panic!("Dummy lookup table has only index 1"),
}
}
fn length(&self) -> usize {
1
}
fn is_fixed(&self) -> bool {
true
}
fn runtime_create_column(&self) -> bool {
panic!("No runtime tables specified");
}
fn ix_by_value<F: PrimeField>(&self, value: &[F]) -> Option<usize> {
if value[0] == F::zero() {
Some(0)
} else {
panic!("Invalid value for DummyLookupTable")
}
}
fn all_variants() -> Vec<Self> {
vec![DummyLookupTable::DummyLookupTable]
}
}
impl DummyLookupTable {
pub fn entries<F: PrimeField>(&self, domain_d1_size: u64) -> Vec<F> {
(0..domain_d1_size).map(|_| F::zero()).collect()
}
}
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum LookupTableIDs {
RangeCheck16,
Custom(u32),
}
impl LookupTableID for LookupTableIDs {
fn to_u32(&self) -> u32 {
match self {
LookupTableIDs::RangeCheck16 => 1_u32,
LookupTableIDs::Custom(id) => id + 1,
}
}
fn from_u32(id: u32) -> Self {
match id {
1 => LookupTableIDs::RangeCheck16,
_ => LookupTableIDs::Custom(id - 1),
}
}
fn length(&self) -> usize {
match self {
LookupTableIDs::RangeCheck16 => 1 << 16,
LookupTableIDs::Custom(_) => todo!(),
}
}
fn is_fixed(&self) -> bool {
true
}
fn runtime_create_column(&self) -> bool {
panic!("No runtime tables specified");
}
fn ix_by_value<F: PrimeField>(&self, _value: &[F]) -> Option<usize> {
todo!()
}
fn all_variants() -> Vec<Self> {
vec![Self::RangeCheck16, Self::Custom(0)]
}
}
pub type Lookup<F> = Logup<F, LookupTableIDs>;
pub type LookupWitness<F> = LogupWitness<F, LookupTableIDs>;
impl<F: FftField> LookupWitness<F> {
pub fn random(domain: EvaluationDomains<F>) -> (LookupTableIDs, Self) {
let mut rng = thread_rng();
let table_size: u64 = rng.gen_range(1..domain.d1.size);
let table_id = rng.gen_range(1..1000);
let t: Vec<u64> = {
let mut n: Vec<u64> = (1..(table_size * 100)).collect();
n.shuffle(&mut rng);
n[0..table_size as usize].to_vec()
};
let f = {
let mut f = t.clone();
f.shuffle(&mut rng);
f
};
let dummy_value = F::rand(&mut rng);
let repeated_dummy_value: Vec<F> = {
let r: Vec<F> = iter::repeat(dummy_value)
.take((domain.d1.size - table_size) as usize)
.collect();
r
};
let t_evals = {
let mut table = Vec::with_capacity(domain.d1.size as usize);
table.extend(t.iter().map(|v| Lookup {
table_id: LookupTableIDs::Custom(table_id),
numerator: -F::one(),
value: vec![F::from(*v)],
}));
table.extend(
repeated_dummy_value
.iter()
.map(|v| Lookup {
table_id: LookupTableIDs::Custom(table_id),
numerator: -F::one(),
value: vec![*v],
})
.collect::<Vec<Lookup<F>>>(),
);
table
};
let f_evals: Vec<Lookup<F>> = {
let mut table = Vec::with_capacity(domain.d1.size as usize);
table.extend(f.iter().map(|v| Lookup {
table_id: LookupTableIDs::Custom(table_id),
numerator: F::one(),
value: vec![F::from(*v)],
}));
table.extend(
repeated_dummy_value
.iter()
.map(|v| Lookup {
table_id: LookupTableIDs::Custom(table_id),
numerator: F::one(),
value: vec![*v],
})
.collect::<Vec<Lookup<F>>>(),
);
table
};
let m = (0..domain.d1.size).map(|_| F::one()).collect();
(
LookupTableIDs::Custom(table_id),
LookupWitness {
f: vec![f_evals, t_evals],
m: vec![m],
},
)
}
}