mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-11 02:03:07 +00:00
Cleanup lookup_test module and reduce module visibility
This commit is contained in:
parent
15064b3aa7
commit
d1c00767bd
@ -12,7 +12,9 @@ pub mod gadgets;
|
||||
pub mod gates;
|
||||
pub mod hash;
|
||||
pub mod iop;
|
||||
pub mod lookup_test;
|
||||
pub mod plonk;
|
||||
pub mod recursion;
|
||||
pub mod util;
|
||||
|
||||
#[cfg(test)]
|
||||
mod lookup_test;
|
||||
|
||||
@ -1,523 +1,477 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
static LOGGER_INITIALIZED: Once = Once::new();
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use std::sync::Once;
|
||||
|
||||
use itertools::Itertools;
|
||||
use log::{Level, LevelFilter};
|
||||
|
||||
use crate::gadgets::lookup::{OTHER_TABLE, SMALLER_TABLE, TIP5_TABLE};
|
||||
use crate::gates::lookup_table::LookupTable;
|
||||
use crate::gates::noop::NoopGate;
|
||||
use crate::plonk::prover::prove;
|
||||
use crate::util::timing::TimingTree;
|
||||
|
||||
#[test]
|
||||
fn test_no_lookup() -> anyhow::Result<()> {
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
use crate::iop::witness::PartialWitness;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
let pw = PartialWitness::new();
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove first", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
timing.print();
|
||||
data.verify(proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_lookup_table_not_used() {
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
builder.add_lookup_table_from_pairs(table);
|
||||
|
||||
builder.build::<C>();
|
||||
}
|
||||
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_lookup_without_table() {
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let dummy = builder.add_virtual_target();
|
||||
builder.add_lookup_from_index(dummy, 0);
|
||||
|
||||
builder.build::<C>();
|
||||
}
|
||||
|
||||
// Tests two lookups in one lookup table.
|
||||
#[test]
|
||||
fn test_one_lookup() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let out_a = table[look_val_a].1;
|
||||
let out_b = table[look_val_b].1;
|
||||
let table_index = builder.add_lookup_table_from_pairs(table);
|
||||
let output_a = builder.add_lookup_from_index(initial_a, table_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, table_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove one lookup", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
timing.print();
|
||||
data.verify(proof.clone())?;
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(out_a),
|
||||
"First lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(out_b),
|
||||
"Second lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Tests one lookup in two different lookup tables.
|
||||
#[test]
|
||||
pub fn test_two_luts() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
|
||||
let first_out = tip5_table[look_val_a];
|
||||
let second_out = tip5_table[look_val_b];
|
||||
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
|
||||
let other_table = OTHER_TABLE.to_vec();
|
||||
|
||||
let table_index = builder.add_lookup_table_from_pairs(table);
|
||||
let output_a = builder.add_lookup_from_index(initial_a, table_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, table_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
let s = first_out + second_out;
|
||||
let final_out = other_table[s as usize];
|
||||
|
||||
let table2: LookupTable = Arc::new((0..256).zip_eq(other_table).collect());
|
||||
let table2_index = builder.add_lookup_table_from_pairs(table2);
|
||||
|
||||
let output_final = builder.add_lookup_from_index(sum, table2_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove two_luts", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
data.verify(proof.clone())?;
|
||||
timing.print();
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(first_out),
|
||||
"First lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[4] == F::from_canonical_u16(second_out),
|
||||
"Second lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(s),
|
||||
"Sum between the first two LUT outputs is incorrect."
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[5] == F::from_canonical_u16(final_out),
|
||||
"Output of the second LUT at index {} is incorrect.",
|
||||
s
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_different_inputs() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let init_a = 1;
|
||||
let init_b = 2;
|
||||
|
||||
let tab: Vec<u16> = SMALLER_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((2..10).zip_eq(tab).collect());
|
||||
|
||||
let other_table = OTHER_TABLE.to_vec();
|
||||
|
||||
let table2: LookupTable = Arc::new((0..256).zip_eq(other_table).collect());
|
||||
let small_index = builder.add_lookup_table_from_pairs(table.clone());
|
||||
let output_a = builder.add_lookup_from_index(initial_a, small_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, small_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
let other_index = builder.add_lookup_table_from_pairs(table2.clone());
|
||||
let output_final = builder.add_lookup_from_index(sum, other_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
let look_val_a = table[init_a].0;
|
||||
let look_val_b = table[init_b].0;
|
||||
pw.set_target(initial_a, F::from_canonical_u16(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_u16(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove different lookups", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
data.verify(proof.clone())?;
|
||||
timing.print();
|
||||
|
||||
let out_a = table[init_a].1;
|
||||
let out_b = table[init_b].1;
|
||||
let s = out_a + out_b;
|
||||
let out_final = table2[s as usize].1;
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(out_a),
|
||||
"First lookup, at index {} in the smaller LUT gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[4] == F::from_canonical_u16(out_b),
|
||||
"Second lookup, at index {} in the smaller LUT gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(s),
|
||||
"Sum between the first two LUT outputs is incorrect."
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[5] == F::from_canonical_u16(out_final),
|
||||
"Output of the second LUT at index {} is incorrect.",
|
||||
s
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This test looks up over 514 values for one LookupTableGate, which means that several LookupGates are created.
|
||||
#[test]
|
||||
pub fn test_many_lookups() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
|
||||
let out_a = table[look_val_a].1;
|
||||
let out_b = table[look_val_b].1;
|
||||
|
||||
let tip5_index = builder.add_lookup_table_from_pairs(table);
|
||||
let output_a = builder.add_lookup_from_index(initial_a, tip5_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, tip5_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
for _ in 0..514 {
|
||||
builder.add_lookup_from_index(initial_a, tip5_index);
|
||||
}
|
||||
|
||||
let other_table = OTHER_TABLE.to_vec();
|
||||
|
||||
let table2: LookupTable = Arc::new((0..256).zip_eq(other_table).collect());
|
||||
|
||||
let s = out_a + out_b;
|
||||
let out_final = table2[s as usize].1;
|
||||
|
||||
let other_index = builder.add_lookup_table_from_pairs(table2);
|
||||
let output_final = builder.add_lookup_from_index(sum, other_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove different lookups", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
|
||||
data.verify(proof.clone())?;
|
||||
timing.print();
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(out_a),
|
||||
"First lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[4] == F::from_canonical_u16(out_b),
|
||||
"Second lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(s),
|
||||
"Sum between the first two LUT outputs is incorrect."
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[5] == F::from_canonical_u16(out_final),
|
||||
"Output of the second LUT at index {} is incorrect.",
|
||||
s
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Tests whether, when adding the same LUT to the circuit, the circuit only adds one copy, with the same index.
|
||||
#[test]
|
||||
pub fn test_same_luts() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
|
||||
let table_index = builder.add_lookup_table_from_pairs(table.clone());
|
||||
let output_a = builder.add_lookup_from_index(initial_a, table_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, table_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
let table2_index = builder.add_lookup_table_from_pairs(table);
|
||||
|
||||
let output_final = builder.add_lookup_from_index(sum, table2_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let luts_length = builder.get_luts_length();
|
||||
|
||||
assert!(
|
||||
luts_length == 1,
|
||||
"There are {} LUTs when there should be only one",
|
||||
luts_length
|
||||
);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove two_luts", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
data.verify(proof)?;
|
||||
timing.print();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_circuit_build_mock() {
|
||||
// This code is taken from examples/fibonacci.rs
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, Witness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
// The arithmetic circuit.
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
let mut prev_target = initial_a;
|
||||
let mut cur_target = initial_b;
|
||||
for _ in 0..99 {
|
||||
let temp = builder.add(prev_target, cur_target);
|
||||
prev_target = cur_target;
|
||||
cur_target = temp;
|
||||
}
|
||||
|
||||
// Public inputs are the two initial values (provided below) and the result (which is generated).
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(cur_target);
|
||||
|
||||
// Provide initial values.
|
||||
let mut pw = PartialWitness::new();
|
||||
pw.set_target(initial_a, F::ZERO);
|
||||
pw.set_target(initial_b, F::ONE);
|
||||
|
||||
let data = builder.mock_build::<C>();
|
||||
let partition_witness = data.generate_witness(pw);
|
||||
let result = partition_witness.try_get_target(cur_target).unwrap();
|
||||
assert_eq!(result, F::from_canonical_u64(3736710860384812976));
|
||||
}
|
||||
|
||||
fn init_logger() -> anyhow::Result<()> {
|
||||
let mut builder = env_logger::Builder::from_default_env();
|
||||
builder.format_timestamp(None);
|
||||
builder.filter_level(LevelFilter::Debug);
|
||||
|
||||
builder.try_init()?;
|
||||
Ok(())
|
||||
}
|
||||
static LOGGER_INITIALIZED: Once = Once::new();
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use std::sync::Once;
|
||||
|
||||
use itertools::Itertools;
|
||||
use log::{Level, LevelFilter};
|
||||
|
||||
use crate::gadgets::lookup::{OTHER_TABLE, SMALLER_TABLE, TIP5_TABLE};
|
||||
use crate::gates::lookup_table::LookupTable;
|
||||
use crate::gates::noop::NoopGate;
|
||||
use crate::plonk::prover::prove;
|
||||
use crate::util::timing::TimingTree;
|
||||
|
||||
#[test]
|
||||
fn test_no_lookup() -> anyhow::Result<()> {
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
use crate::iop::witness::PartialWitness;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
builder.add_gate(NoopGate, vec![]);
|
||||
let pw = PartialWitness::new();
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove first", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
timing.print();
|
||||
data.verify(proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_lookup_table_not_used() {
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
builder.add_lookup_table_from_pairs(table);
|
||||
|
||||
builder.build::<C>();
|
||||
}
|
||||
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_lookup_without_table() {
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let dummy = builder.add_virtual_target();
|
||||
builder.add_lookup_from_index(dummy, 0);
|
||||
|
||||
builder.build::<C>();
|
||||
}
|
||||
|
||||
// Tests two lookups in one lookup table.
|
||||
#[test]
|
||||
fn test_one_lookup() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let out_a = table[look_val_a].1;
|
||||
let out_b = table[look_val_b].1;
|
||||
let table_index = builder.add_lookup_table_from_pairs(table);
|
||||
let output_a = builder.add_lookup_from_index(initial_a, table_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, table_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove one lookup", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
timing.print();
|
||||
data.verify(proof.clone())?;
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(out_a),
|
||||
"First lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(out_b),
|
||||
"Second lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Tests one lookup in two different lookup tables.
|
||||
#[test]
|
||||
pub fn test_two_luts() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
|
||||
let first_out = tip5_table[look_val_a];
|
||||
let second_out = tip5_table[look_val_b];
|
||||
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
|
||||
let other_table = OTHER_TABLE.to_vec();
|
||||
|
||||
let table_index = builder.add_lookup_table_from_pairs(table);
|
||||
let output_a = builder.add_lookup_from_index(initial_a, table_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, table_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
let s = first_out + second_out;
|
||||
let final_out = other_table[s as usize];
|
||||
|
||||
let table2: LookupTable = Arc::new((0..256).zip_eq(other_table).collect());
|
||||
let table2_index = builder.add_lookup_table_from_pairs(table2);
|
||||
|
||||
let output_final = builder.add_lookup_from_index(sum, table2_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove two_luts", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
data.verify(proof.clone())?;
|
||||
timing.print();
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(first_out),
|
||||
"First lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[4] == F::from_canonical_u16(second_out),
|
||||
"Second lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(s),
|
||||
"Sum between the first two LUT outputs is incorrect."
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[5] == F::from_canonical_u16(final_out),
|
||||
"Output of the second LUT at index {} is incorrect.",
|
||||
s
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_different_inputs() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let init_a = 1;
|
||||
let init_b = 2;
|
||||
|
||||
let tab: Vec<u16> = SMALLER_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((2..10).zip_eq(tab).collect());
|
||||
|
||||
let other_table = OTHER_TABLE.to_vec();
|
||||
|
||||
let table2: LookupTable = Arc::new((0..256).zip_eq(other_table).collect());
|
||||
let small_index = builder.add_lookup_table_from_pairs(table.clone());
|
||||
let output_a = builder.add_lookup_from_index(initial_a, small_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, small_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
let other_index = builder.add_lookup_table_from_pairs(table2.clone());
|
||||
let output_final = builder.add_lookup_from_index(sum, other_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
let look_val_a = table[init_a].0;
|
||||
let look_val_b = table[init_b].0;
|
||||
pw.set_target(initial_a, F::from_canonical_u16(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_u16(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove different lookups", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
data.verify(proof.clone())?;
|
||||
timing.print();
|
||||
|
||||
let out_a = table[init_a].1;
|
||||
let out_b = table[init_b].1;
|
||||
let s = out_a + out_b;
|
||||
let out_final = table2[s as usize].1;
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(out_a),
|
||||
"First lookup, at index {} in the smaller LUT gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[4] == F::from_canonical_u16(out_b),
|
||||
"Second lookup, at index {} in the smaller LUT gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(s),
|
||||
"Sum between the first two LUT outputs is incorrect."
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[5] == F::from_canonical_u16(out_final),
|
||||
"Output of the second LUT at index {} is incorrect.",
|
||||
s
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This test looks up over 514 values for one LookupTableGate, which means that several LookupGates are created.
|
||||
#[test]
|
||||
pub fn test_many_lookups() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
|
||||
let out_a = table[look_val_a].1;
|
||||
let out_b = table[look_val_b].1;
|
||||
|
||||
let tip5_index = builder.add_lookup_table_from_pairs(table);
|
||||
let output_a = builder.add_lookup_from_index(initial_a, tip5_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, tip5_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
for _ in 0..514 {
|
||||
builder.add_lookup_from_index(initial_a, tip5_index);
|
||||
}
|
||||
|
||||
let other_table = OTHER_TABLE.to_vec();
|
||||
|
||||
let table2: LookupTable = Arc::new((0..256).zip_eq(other_table).collect());
|
||||
|
||||
let s = out_a + out_b;
|
||||
let out_final = table2[s as usize].1;
|
||||
|
||||
let other_index = builder.add_lookup_table_from_pairs(table2);
|
||||
let output_final = builder.add_lookup_from_index(sum, other_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove different lookups", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
|
||||
data.verify(proof.clone())?;
|
||||
timing.print();
|
||||
|
||||
assert!(
|
||||
proof.public_inputs[3] == F::from_canonical_u16(out_a),
|
||||
"First lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[0]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[4] == F::from_canonical_u16(out_b),
|
||||
"Second lookup, at index {} in the Tip5 table gives an incorrect output.",
|
||||
proof.public_inputs[1]
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[2] == F::from_canonical_u16(s),
|
||||
"Sum between the first two LUT outputs is incorrect."
|
||||
);
|
||||
assert!(
|
||||
proof.public_inputs[5] == F::from_canonical_u16(out_final),
|
||||
"Output of the second LUT at index {} is incorrect.",
|
||||
s
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Tests whether, when adding the same LUT to the circuit, the circuit only adds one copy, with the same index.
|
||||
#[test]
|
||||
pub fn test_same_luts() -> anyhow::Result<()> {
|
||||
use crate::field::types::Field;
|
||||
use crate::iop::witness::{PartialWitness, WitnessWrite};
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
LOGGER_INITIALIZED.call_once(|| init_logger().unwrap());
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let initial_a = builder.add_virtual_target();
|
||||
let initial_b = builder.add_virtual_target();
|
||||
|
||||
let look_val_a = 1;
|
||||
let look_val_b = 2;
|
||||
|
||||
let tip5_table = TIP5_TABLE.to_vec();
|
||||
let table: LookupTable = Arc::new((0..256).zip_eq(tip5_table).collect());
|
||||
|
||||
let table_index = builder.add_lookup_table_from_pairs(table.clone());
|
||||
let output_a = builder.add_lookup_from_index(initial_a, table_index);
|
||||
|
||||
let output_b = builder.add_lookup_from_index(initial_b, table_index);
|
||||
let sum = builder.add(output_a, output_b);
|
||||
|
||||
let table2_index = builder.add_lookup_table_from_pairs(table);
|
||||
|
||||
let output_final = builder.add_lookup_from_index(sum, table2_index);
|
||||
|
||||
builder.register_public_input(initial_a);
|
||||
builder.register_public_input(initial_b);
|
||||
builder.register_public_input(sum);
|
||||
builder.register_public_input(output_a);
|
||||
builder.register_public_input(output_b);
|
||||
builder.register_public_input(output_final);
|
||||
|
||||
let luts_length = builder.get_luts_length();
|
||||
|
||||
assert!(
|
||||
luts_length == 1,
|
||||
"There are {} LUTs when there should be only one",
|
||||
luts_length
|
||||
);
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
|
||||
pw.set_target(initial_a, F::from_canonical_usize(look_val_a));
|
||||
pw.set_target(initial_b, F::from_canonical_usize(look_val_b));
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let mut timing = TimingTree::new("prove two_luts", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
data.verify(proof)?;
|
||||
timing.print();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_logger() -> anyhow::Result<()> {
|
||||
let mut builder = env_logger::Builder::from_default_env();
|
||||
builder.format_timestamp(None);
|
||||
builder.filter_level(LevelFilter::Debug);
|
||||
|
||||
builder.try_init()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user