use super::*;
use crate::bellman::plonk::better_better_cs::lookup_tables::*;
use itertools::Itertools;
#[derive(Clone)]
pub struct CombinedBitwiseLogicRangeTable<E: Engine> {
table_entries: [Vec<E::Fr>; 3],
table_lookup_map: std::collections::HashMap<(E::Fr, E::Fr), E::Fr>,
bits: usize,
name: &'static str,
}
impl<E: Engine> CombinedBitwiseLogicRangeTable<E> {
pub fn new(name: &'static str, bits: usize) -> Self {
let table_len = 1 << (2 * bits);
let var_range = 1 << bits;
let mut keys0 = Vec::with_capacity(table_len);
let mut keys1 = Vec::with_capacity(table_len);
let mut values = Vec::with_capacity(table_len);
let mut map = std::collections::HashMap::with_capacity(table_len);
for (x, y) in (0..var_range).cartesian_product(0..var_range) {
let res_and = (x & y) as u64;
let res_or = (x | y) as u64;
let res_xor = (x ^ y) as u64;
let z = res_and + (res_or << 16) + (res_xor << 32);
let x = u64_to_fe(x as u64);
let y = u64_to_fe(y as u64);
let z = u64_to_fe(z as u64);
keys0.push(x);
keys1.push(y);
values.push(z);
map.insert((x, y), z);
}
Self {
table_entries: [keys0, keys1, values],
table_lookup_map: map,
bits,
name,
}
}
}
impl<E: Engine> std::fmt::Debug for CombinedBitwiseLogicRangeTable<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CombinedBitwiseLogicRangeTable").field("bits", &self.bits).finish()
}
}
impl<E: Engine> LookupTableInternal<E> for CombinedBitwiseLogicRangeTable<E> {
fn name(&self) -> &'static str {
self.name
}
fn table_size(&self) -> usize {
1 << (2 * self.bits)
}
fn num_keys(&self) -> usize {
2
}
fn num_values(&self) -> usize {
1
}
fn allows_combining(&self) -> bool {
true
}
fn get_table_values_for_polys(&self) -> Vec<Vec<E::Fr>> {
vec![self.table_entries[0].clone(), self.table_entries[1].clone(), self.table_entries[2].clone()]
}
fn table_id(&self) -> E::Fr {
table_id_from_string(self.name)
}
fn sort(&self, _values: &[E::Fr], _column: usize) -> Result<Vec<E::Fr>, SynthesisError> {
unimplemented!()
}
fn box_clone(&self) -> Box<dyn LookupTableInternal<E>> {
Box::from(self.clone())
}
fn column_is_trivial(&self, column_num: usize) -> bool {
assert!(column_num <= 2);
false
}
fn is_valid_entry(&self, keys: &[E::Fr], values: &[E::Fr]) -> bool {
assert!(keys.len() == self.num_keys());
assert!(values.len() == self.num_values());
if let Some(entry) = self.table_lookup_map.get(&(keys[0], keys[1])) {
return entry == &(values[0]);
}
false
}
fn query(&self, keys: &[E::Fr]) -> Result<Vec<E::Fr>, SynthesisError> {
assert!(keys.len() == self.num_keys());
if let Some(entry) = self.table_lookup_map.get(&(keys[0], keys[1])) {
return Ok(vec![*entry]);
}
Err(SynthesisError::Unsatisfiable)
}
}