Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

✨ add EC and modexp precompiles #143

Open
wants to merge 4 commits into
base: dl-precompiles
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
✨ add EC precompiles
ZamDimon authored and NikitaMasych committed May 27, 2024
commit 12a6b87bad9637bebc013e2a5b13f5d4a880354a
4 changes: 2 additions & 2 deletions circuit_definitions/Cargo.toml
Original file line number Diff line number Diff line change
@@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
snark_wrapper = {git = "https://github.com/matter-labs/snark-wrapper.git", branch = "main"}
# snark_wrapper = {path = "../../snark_wrapper"}
# snark_wrapper = {git = "https://github.com/matter-labs/snark-wrapper.git", branch = "main"}
snark_wrapper = {path = "../../snark-wrapper"}

circuit_encodings = {path = "../circuit_encodings"}

178 changes: 178 additions & 0 deletions circuit_definitions/src/circuit_definitions/base_layer/ecadd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
use crate::zkevm_circuits::bn254::ec_add::input::EcAddCircuitInstanceWitness;
use circuit_encodings::zkevm_circuits::bn254::{
ec_add::ecadd_function_entry_point,
fixed_base_mul_table::{create_fixed_base_mul_table, FixedBaseMulTable},
};
use derivative::*;

use super::*;
use crate::boojum::cs::traits::circuit::CircuitBuilder;

type F = GoldilocksField;
type R = Poseidon2Goldilocks;

#[derive(Derivative, serde::Serialize, serde::Deserialize)]
#[derivative(Clone, Copy, Debug, Default(bound = ""))]
pub struct ECAddFunctionInstanceSynthesisFunction {
_marker: std::marker::PhantomData<(F, R)>,
}

impl CircuitBuilder<F> for ECAddFunctionInstanceSynthesisFunction
where
[(); <LogQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <MemoryQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <DecommitQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN + 1]:,
{
fn geometry() -> CSGeometry {
CSGeometry {
num_columns_under_copy_permutation: 200,
num_witness_columns: 0,
num_constant_columns: 8,
max_allowed_constraint_degree: 4,
}
}

fn lookup_parameters() -> LookupParameters {
LookupParameters::UseSpecializedColumnsWithTableIdAsConstant {
width: 3,
num_repetitions: 8,
share_table_id: true,
}
}

fn configure_builder<
T: CsBuilderImpl<F, T>,
GC: GateConfigurationHolder<F>,
TB: StaticToolboxHolder,
>(
builder: CsBuilder<T, F, GC, TB>,
) -> CsBuilder<T, F, impl GateConfigurationHolder<F>, impl StaticToolboxHolder> {
// TODO: Maybe some gates are not actually needed since it was copy-pasting from the previous secp256k1 ecmul implementation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can check if this is the case or not by running a full proof of the circuit and then printing the gate stats - it should give you a tally of how often each gate is called

let builder = builder.allow_lookup(<Self as CircuitBuilder<F>>::lookup_parameters());

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 owned_cs = ReductionGate::<F, 4>::configure_for_cs(owned_cs, GatePlacementStrategy::UseSpecializedColumns { num_repetitions: 8, share_constants: true });
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
}
}

impl ZkSyncUniformSynthesisFunction<F> for ECAddFunctionInstanceSynthesisFunction
where
[(); <LogQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <MemoryQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <DecommitQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN + 1]:,
{
type Witness = EcAddCircuitInstanceWitness<F>;
type Config = usize;
type RoundFunction = R;

fn description() -> String {
"Elliptic Curve Addition".to_string()
}

fn size_hint() -> (Option<usize>, Option<usize>) {
(Some(TARGET_CIRCUIT_TRACE_LENGTH), Some(1 << 26))
}

fn add_tables<CS: ConstraintSystem<F>>(cs: &mut CS) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are any of these tables actually necessary? i thought ecadd only uses gates and it seems useless to add byte splits, bitwise ops and fixed base muls

// let table = create_range_check_table::<F, 8>();
// cs.add_lookup_table::<RangeCheckTable<8>, 1>(table);

// let table = create_range_check_16_bits_table::<F>();
// cs.add_lookup_table::<RangeCheck16BitsTable, 1>(table);

let table = create_xor8_table();
cs.add_lookup_table::<Xor8Table, 3>(table);

let table = create_and8_table();
cs.add_lookup_table::<And8Table, 3>(table);

seq_macro::seq!(C in 0..32 {
let table = create_fixed_base_mul_table::<F, 0, C>();
cs.add_lookup_table::<FixedBaseMulTable<0, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 1, C>();
cs.add_lookup_table::<FixedBaseMulTable<1, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 2, C>();
cs.add_lookup_table::<FixedBaseMulTable<2, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 3, C>();
cs.add_lookup_table::<FixedBaseMulTable<3, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 4, C>();
cs.add_lookup_table::<FixedBaseMulTable<4, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 5, C>();
cs.add_lookup_table::<FixedBaseMulTable<5, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 6, C>();
cs.add_lookup_table::<FixedBaseMulTable<6, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 7, C>();
cs.add_lookup_table::<FixedBaseMulTable<7, C>, 3>(table);
});

let table = create_byte_split_table::<F, 1>();
cs.add_lookup_table::<ByteSplitTable<1>, 3>(table);
let table = create_byte_split_table::<F, 2>();
cs.add_lookup_table::<ByteSplitTable<2>, 3>(table);
let table = create_byte_split_table::<F, 3>();
cs.add_lookup_table::<ByteSplitTable<3>, 3>(table);
let table = create_byte_split_table::<F, 4>();
cs.add_lookup_table::<ByteSplitTable<4>, 3>(table);
}

fn synthesize_into_cs_inner<CS: ConstraintSystem<F>>(
cs: &mut CS,
witness: Self::Witness,
round_function: &Self::RoundFunction,
config: Self::Config,
) -> [Num<F>; INPUT_OUTPUT_COMMITMENT_LENGTH] {
ecadd_function_entry_point(cs, witness, round_function, config)
}
}
177 changes: 177 additions & 0 deletions circuit_definitions/src/circuit_definitions/base_layer/ecmul.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use circuit_encodings::zkevm_circuits::bn254::{
ec_mul::{ecmul_function_entry_point, input::EcMulCircuitInstanceWitness},
fixed_base_mul_table::{create_fixed_base_mul_table, FixedBaseMulTable},
};
use derivative::*;

use super::*;
use crate::boojum::cs::traits::circuit::CircuitBuilder;

type F = GoldilocksField;
type R = Poseidon2Goldilocks;

#[derive(Derivative, serde::Serialize, serde::Deserialize)]
#[derivative(Clone, Copy, Debug, Default(bound = ""))]
pub struct ECMulFunctionInstanceSynthesisFunction {
_marker: std::marker::PhantomData<(F, R)>,
}

impl CircuitBuilder<F> for ECMulFunctionInstanceSynthesisFunction
where
[(); <LogQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <MemoryQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <DecommitQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN + 1]:,
{
fn geometry() -> CSGeometry {
CSGeometry {
num_columns_under_copy_permutation: 200,
num_witness_columns: 0,
num_constant_columns: 8,
max_allowed_constraint_degree: 4,
}
}

fn lookup_parameters() -> LookupParameters {
LookupParameters::UseSpecializedColumnsWithTableIdAsConstant {
width: 3,
num_repetitions: 8,
share_table_id: true,
}
}

fn configure_builder<
T: CsBuilderImpl<F, T>,
GC: GateConfigurationHolder<F>,
TB: StaticToolboxHolder,
>(
builder: CsBuilder<T, F, GC, TB>,
) -> CsBuilder<T, F, impl GateConfigurationHolder<F>, impl StaticToolboxHolder> {
// TODO: Maybe some gates are not actually needed since it was copy-pasting from the previous secp256k1 ecmul implementation.
let builder = builder.allow_lookup(<Self as CircuitBuilder<F>>::lookup_parameters());

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 owned_cs = ReductionGate::<F, 4>::configure_for_cs(owned_cs, GatePlacementStrategy::UseSpecializedColumns { num_repetitions: 8, share_constants: true });
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
}
}

impl ZkSyncUniformSynthesisFunction<F> for ECMulFunctionInstanceSynthesisFunction
where
[(); <LogQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <MemoryQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <DecommitQuery<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN]:,
[(); <UInt256<F> as CSAllocatableExt<F>>::INTERNAL_STRUCT_LEN + 1]:,
{
type Witness = EcMulCircuitInstanceWitness<F>;
type Config = usize;
type RoundFunction = R;

fn description() -> String {
"Elliptic Curve Multiplication".to_string()
}

fn size_hint() -> (Option<usize>, Option<usize>) {
(Some(TARGET_CIRCUIT_TRACE_LENGTH), Some(1 << 26))
}

fn add_tables<CS: ConstraintSystem<F>>(cs: &mut CS) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i assume it's the same case with gates and tables here but these should be checked and removed before merging on each new circuit

// let table = create_range_check_table::<F, 8>();
// cs.add_lookup_table::<RangeCheckTable<8>, 1>(table);

// let table = create_range_check_16_bits_table::<F>();
// cs.add_lookup_table::<RangeCheck16BitsTable, 1>(table);

let table = create_xor8_table();
cs.add_lookup_table::<Xor8Table, 3>(table);

let table = create_and8_table();
cs.add_lookup_table::<And8Table, 3>(table);

seq_macro::seq!(C in 0..32 {
let table = create_fixed_base_mul_table::<F, 0, C>();
cs.add_lookup_table::<FixedBaseMulTable<0, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 1, C>();
cs.add_lookup_table::<FixedBaseMulTable<1, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 2, C>();
cs.add_lookup_table::<FixedBaseMulTable<2, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 3, C>();
cs.add_lookup_table::<FixedBaseMulTable<3, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 4, C>();
cs.add_lookup_table::<FixedBaseMulTable<4, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 5, C>();
cs.add_lookup_table::<FixedBaseMulTable<5, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 6, C>();
cs.add_lookup_table::<FixedBaseMulTable<6, C>, 3>(table);
let table = create_fixed_base_mul_table::<F, 7, C>();
cs.add_lookup_table::<FixedBaseMulTable<7, C>, 3>(table);
});

let table = create_byte_split_table::<F, 1>();
cs.add_lookup_table::<ByteSplitTable<1>, 3>(table);
let table = create_byte_split_table::<F, 2>();
cs.add_lookup_table::<ByteSplitTable<2>, 3>(table);
let table = create_byte_split_table::<F, 3>();
cs.add_lookup_table::<ByteSplitTable<3>, 3>(table);
let table = create_byte_split_table::<F, 4>();
cs.add_lookup_table::<ByteSplitTable<4>, 3>(table);
}

fn synthesize_into_cs_inner<CS: ConstraintSystem<F>>(
cs: &mut CS,
witness: Self::Witness,
round_function: &Self::RoundFunction,
config: Self::Config,
) -> [Num<F>; INPUT_OUTPUT_COMMITMENT_LENGTH] {
ecmul_function_entry_point(cs, witness, round_function, config)
}
}
Loading