pub mod test {
use boojum::config::DevCSConfig;
use boojum::cs::cs_builder::{new_builder, CsBuilder, CsBuilderImpl};
use boojum::cs::cs_builder_reference::CsReferenceImplementationBuilder;
use boojum::cs::gates::{
BooleanConstraintGate, ConstantsAllocatorGate, DotProductGate,
FmaGateInBaseFieldWithoutConstant, NopGate, ReductionGate, SelectionGate, U8x4FMAGate,
UIntXAddGate, ZeroCheckGate,
};
use boojum::cs::implementations::reference_cs::CSReferenceImplementation;
use boojum::cs::traits::cs::ConstraintSystem;
use boojum::cs::traits::gate::GatePlacementStrategy;
use boojum::cs::{CSGeometry, GateConfigurationHolder, LookupParameters, StaticToolboxHolder};
use boojum::field::goldilocks::GoldilocksField;
use boojum::field::SmallField;
use boojum::gadgets::boolean::Boolean;
use boojum::gadgets::tables::{
create_and8_table, create_byte_split_table, create_xor8_table, And8Table, ByteSplitTable,
Xor8Table,
};
use boojum::gadgets::u256::UInt256;
use crate::modexp::implementation::u256::modexp_32_32_32;
use crate::modexp::tests_json::u256::{Modexp32BytesLargeExpTestCase, Modmul32BytesTestCase};
use crate::modexp::tests_json::{MODEXP_32_32_32_TEST_CASES, MODMUL_32_32_TEST_CASES};
type F = GoldilocksField;
type P = GoldilocksField;
pub fn create_test_cs(
max_trace_len: usize,
) -> CSReferenceImplementation<
F,
P,
DevCSConfig,
impl GateConfigurationHolder<F>,
impl StaticToolboxHolder,
> {
let geometry = CSGeometry {
num_columns_under_copy_permutation: 200,
num_witness_columns: 0,
num_constant_columns: 8,
max_allowed_constraint_degree: 4,
};
let max_variables = 1 << 26;
fn configure<
F: SmallField,
T: CsBuilderImpl<F, T>,
GC: GateConfigurationHolder<F>,
TB: StaticToolboxHolder,
>(
builder: CsBuilder<T, F, GC, TB>,
) -> CsBuilder<T, F, impl GateConfigurationHolder<F>, impl StaticToolboxHolder> {
let builder = builder.allow_lookup(
LookupParameters::UseSpecializedColumnsWithTableIdAsConstant {
width: 3,
num_repetitions: 8,
share_table_id: true,
},
);
let builder = U8x4FMAGate::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = ConstantsAllocatorGate::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = FmaGateInBaseFieldWithoutConstant::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = ReductionGate::<F, 4>::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = BooleanConstraintGate::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = UIntXAddGate::<32>::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = UIntXAddGate::<16>::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = UIntXAddGate::<8>::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = SelectionGate::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = ZeroCheckGate::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
false,
);
let builder = DotProductGate::<4>::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
let builder = NopGate::configure_builder(
builder,
GatePlacementStrategy::UseGeneralPurposeColumns,
);
builder
}
let builder_impl =
CsReferenceImplementationBuilder::<F, P, DevCSConfig>::new(geometry, max_trace_len);
let builder = new_builder::<_, F>(builder_impl);
let builder = configure(builder);
let mut owned_cs = builder.build(max_variables);
let table = create_xor8_table();
owned_cs.add_lookup_table::<Xor8Table, 3>(table);
let table = create_and8_table();
owned_cs.add_lookup_table::<And8Table, 3>(table);
let table = create_byte_split_table::<F, 1>();
owned_cs.add_lookup_table::<ByteSplitTable<1>, 3>(table);
let table = create_byte_split_table::<F, 2>();
owned_cs.add_lookup_table::<ByteSplitTable<2>, 3>(table);
let table = create_byte_split_table::<F, 3>();
owned_cs.add_lookup_table::<ByteSplitTable<3>, 3>(table);
let table = create_byte_split_table::<F, 4>();
owned_cs.add_lookup_table::<ByteSplitTable<4>, 3>(table);
let table = create_byte_split_table::<F, 7>();
owned_cs.add_lookup_table::<ByteSplitTable<7>, 3>(table);
owned_cs
}
fn assert_equal_uint256<CS>(cs: &mut CS, a: &UInt256<F>, b: &UInt256<F>)
where
CS: ConstraintSystem<F>,
{
let equals = UInt256::equals(cs, a, b);
let boolean_true = Boolean::allocated_constant(cs, true);
Boolean::enforce_equal(cs, &equals, &boolean_true);
}
#[test]
fn test_modexp_32_32_32() {
let mut owned_cs = create_test_cs(1 << 20);
let cs = &mut owned_cs;
for (_, raw) in MODEXP_32_32_32_TEST_CASES.tests.iter().enumerate() {
let test = Modexp32BytesLargeExpTestCase::from_raw(cs, &raw);
let actual_modexp = modexp_32_32_32(cs, &test.base, &test.exponent, &test.modulus);
let expected_modexp = test.expected.clone();
assert_equal_uint256(cs, &actual_modexp, &expected_modexp);
}
}
#[test]
fn test_modmul_32_32() {
let mut owned_cs = create_test_cs(1 << 20);
let cs = &mut owned_cs;
for (_, raw) in MODMUL_32_32_TEST_CASES.tests.iter().enumerate() {
let test = Modmul32BytesTestCase::from_raw(cs, &raw);
let actual_modmul = test.a.modmul(cs, &test.b, &test.modulus);
let expected_modmul = test.expected.clone();
assert_equal_uint256(cs, &actual_modmul, &expected_modmul);
}
}
#[test]
#[ignore = "debugs the performance, should be run manually"]
fn debug_modmul_32_32_performance() {
let mut owned_cs = create_test_cs(1 << 20);
let cs = &mut owned_cs;
let raw = &MODMUL_32_32_TEST_CASES.tests[0];
let test_case = Modmul32BytesTestCase::from_raw(cs, &raw);
let _ = test_case.a.modmul(cs, &test_case.b, &test_case.modulus);
let cs = owned_cs.into_assembly::<std::alloc::Global>();
cs.print_gate_stats();
}
}