Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions zkevm-circuits/src/evm_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ pub(crate) mod test {
FixedTableTag::Range512,
FixedTableTag::SignByte,
FixedTableTag::ResponsibleOpcode,
FixedTableTag::Bitslevel,
FixedTableTag::Pow64,
],
)
}
Expand Down
5 changes: 5 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod mul;
mod pc;
mod pop;
mod push;
mod shl;
mod signed_comparator;
mod signextend;
mod stop;
Expand All @@ -58,6 +59,7 @@ use mul::MulGadget;
use pc::PcGadget;
use pop::PopGadget;
use push::PushGadget;
use shl::ShlGadget;
use signed_comparator::SignedComparatorGadget;
use signextend::SignextendGadget;
use stop::StopGadget;
Expand Down Expand Up @@ -104,6 +106,7 @@ pub(crate) struct ExecutionConfig<F> {
pc_gadget: PcGadget<F>,
pop_gadget: PopGadget<F>,
push_gadget: PushGadget<F>,
shl_gadget: ShlGadget<F>,
signed_comparator_gadget: SignedComparatorGadget<F>,
signextend_gadget: SignextendGadget<F>,
stop_gadget: StopGadget<F>,
Expand Down Expand Up @@ -232,6 +235,7 @@ impl<F: FieldExt> ExecutionConfig<F> {
pc_gadget: configure_gadget!(),
pop_gadget: configure_gadget!(),
push_gadget: configure_gadget!(),
shl_gadget: configure_gadget!(),
signed_comparator_gadget: configure_gadget!(),
signextend_gadget: configure_gadget!(),
stop_gadget: configure_gadget!(),
Expand Down Expand Up @@ -464,6 +468,7 @@ impl<F: FieldExt> ExecutionConfig<F> {
ExecutionState::ADD => assign_exec_step!(self.add_gadget),
ExecutionState::MUL => assign_exec_step!(self.mul_gadget),
ExecutionState::BITWISE => assign_exec_step!(self.bitwise_gadget),
ExecutionState::SHL => assign_exec_step!(self.shl_gadget),
ExecutionState::SIGNEXTEND => {
assign_exec_step!(self.signextend_gadget)
}
Expand Down
114 changes: 114 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution/shl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use crate::{
evm_circuit::{
execution::ExecutionGadget,
step::ExecutionState,
util::{
common_gadget::SameContextGadget,
constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta},
math_gadget::ShlWordsGadget,
},
witness::{Block, Call, ExecStep, Transaction},
},
util::Expr,
};
use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};

#[derive(Clone, Debug)]
pub(crate) struct ShlGadget<F> {
same_context: SameContextGadget<F>,
shl_words: ShlWordsGadget<F>,
}

impl<F: FieldExt> ExecutionGadget<F> for ShlGadget<F> {
const NAME: &'static str = "SHL";

const EXECUTION_STATE: ExecutionState = ExecutionState::SHL;

fn configure(cb: &mut ConstraintBuilder<F>) -> Self {
let opcode = cb.query_cell();

let a = cb.query_word();
let shift = cb.query_word();

cb.stack_pop(shift.expr());
cb.stack_pop(a.expr());
let shl_words = ShlWordsGadget::construct(cb, a, shift);
cb.stack_push(shl_words.b().expr());

let step_state_transition = StepStateTransition {
rw_counter: Delta(3.expr()),
program_counter: Delta(1.expr()),
stack_pointer: Delta(1.expr()),
..Default::default()
};
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition, None);

Self {
same_context,
shl_words,
}
}

fn assign_exec_step(
&self,
region: &mut Region<'_, F>,
offset: usize,
block: &Block<F>,
_: &Transaction<F>,
_: &Call<F>,
step: &ExecStep,
) -> Result<(), Error> {
self.same_context.assign_exec_step(region, offset, step)?;
let indices = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]];
let [shift, a, b] = indices.map(|idx| block.rws[idx].stack_value());
self.shl_words.assign(region, offset, a, shift, b)
}
}

#[cfg(test)]
mod test {
use crate::evm_circuit::test::rand_word;
use crate::test_util::run_test_circuits;
use eth_types::evm_types::OpcodeId;
use eth_types::{bytecode, Word};
use rand::Rng;

fn test_ok(opcode: OpcodeId, a: Word, shift: Word) {
let bytecode = bytecode! {
PUSH32(a)
PUSH32(shift)
#[start]
.write_op(opcode)
STOP
};
assert_eq!(run_test_circuits(bytecode), Ok(()));
}

#[test]
fn shl_gadget_simple() {
test_ok(OpcodeId::SHL, 0x02FF.into(), 0x1.into());
}

#[test]
fn shl_gadget_rand_normal_shift() {
let a = rand_word();
let mut rng = rand::thread_rng();
let shift = rng.gen_range(0..=255);
test_ok(OpcodeId::SHL, a, shift.into());
}

#[test]
fn shl_gadget_rand_overflow_shift() {
let a = rand_word();
let shift = Word::from_big_endian(&[255u8; 32]);
test_ok(OpcodeId::SHL, a, shift);
}

//this testcase manage to check the split is correct.
#[test]
fn shl_gadget_constant_shift() {
let a = rand_word();
test_ok(OpcodeId::SHL, a, 8.into());
test_ok(OpcodeId::SHL, a, 64.into());
}
}
15 changes: 15 additions & 0 deletions zkevm-circuits/src/evm_circuit/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub enum FixedTableTag {
BitwiseOr,
BitwiseXor,
ResponsibleOpcode,
Bitslevel,
Pow64,
}

impl FixedTableTag {
Expand All @@ -46,6 +48,8 @@ impl FixedTableTag {
Self::BitwiseOr,
Self::BitwiseXor,
Self::ResponsibleOpcode,
Self::Bitslevel,
Self::Pow64,
]
.iter()
.copied()
Expand Down Expand Up @@ -98,6 +102,17 @@ impl FixedTableTag {
})
}))
}
Self::Bitslevel => Box::new((0..9).flat_map(move |level| {
(0..(1 << level)).map(move |idx| [tag, F::from(level), F::from(idx), F::zero()])
})),
Self::Pow64 => Box::new((0..64).map(move |idx| {
[
tag,
F::from(idx),
F::from_u128(1u128 << idx),
F::from_u128(1u128 << (64 - idx)),
]
})),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/util/constraint_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use halo2::{arithmetic::FieldExt, plonk::Expression};
use std::convert::TryInto;

// Max degree allowed in all expressions passing through the ConstraintBuilder.
const MAX_DEGREE: usize = 2usize.pow(3) + 1;
const MAX_DEGREE: usize = 2usize.pow(3) + 3;
// Degree added for expressions used in lookups.
const LOOKUP_DEGREE: usize = 3;

Expand Down
Loading