Skip to content

Commit 81375f5

Browse files
joonazankoloz193Raid5594
authored
feat: Elliptic curve precompiles (#87)
Adds elliptic curve precompiles support. --------- Co-authored-by: koloz <zach.kolodny@gmail.com> Co-authored-by: Raid5594 <52794079+Raid5594@users.noreply.github.com> Co-authored-by: Raid Ateir <ateirraid@gmail.com>
1 parent 8311047 commit 81375f5

File tree

9 files changed

+384
-247
lines changed

9 files changed

+384
-247
lines changed

Cargo.lock

Lines changed: 320 additions & 226 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ primitive-types = "0.12.1"
3030
proptest = "1.4"
3131

3232
# "Internal" dependencies
33-
zkevm_opcode_defs = "0.151.3"
34-
zk_evm_abstractions = "0.151.3"
35-
zk_evm = "0.151.3"
33+
zkevm_opcode_defs = "0.152.0"
34+
zk_evm_abstractions = "0.152.0"
35+
zk_evm = "0.152.0"
3636

3737
# Dependencies within the workspace
3838
zksync_vm2_interface = { version = "0.3.0", path = "crates/vm2-interface" }

crates/vm2-interface/src/tracer_interface.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,14 @@ pub enum CycleStats {
313313
EcRecover(u32),
314314
/// Call to the `secp256r1_verify` precompile with the specified number of hash cycles.
315315
Secp256r1Verify(u32),
316+
/// Call to the `modexp` precompile took the specified number of cycles.
317+
ModExp(u32),
318+
/// Call to the `ecadd` precompile took the specified number of cycles.
319+
EcAdd(u32),
320+
/// Call to the `ecmul` precompile took the specified number of cycles.
321+
EcMul(u32),
322+
/// Call to the `ecpairing` precompile took the specified number of cycles.
323+
EcPairing(u32),
316324
/// Decommitting an opcode.
317325
Decommit(u32),
318326
/// Reading a slot from the VM storage.

crates/vm2/src/callframe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ impl<T, W> PartialEq for Callframe<T, W> {
281281
&& self.sp == other.sp
282282
&& self.gas == other.gas
283283
&& self.near_calls == other.near_calls
284-
&& self.pc == other.pc
284+
&& std::ptr::eq(self.pc, other.pc)
285285
&& self.program == other.program
286286
&& self.heap == other.heap
287287
&& self.aux_heap == other.aux_heap

crates/vm2/src/instruction_handlers/far_call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ where
8383
vm.state.current_frame.gas = 0;
8484
mandated_gas = 0;
8585
return None;
86-
};
86+
}
8787

8888
if IS_SHARD && abi.shard_id != 0 {
8989
return None;

crates/vm2/src/instruction_handlers/heap_access.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn load<T: Tracer, W: World<T>, H: HeapFromState, In: Source, const INCREMENT: b
8585
if grow_heap::<_, _, H>(&mut vm.state, new_bound).is_err() {
8686
vm.state.current_frame.pc = spontaneous_panic();
8787
return;
88-
};
88+
}
8989

9090
let heap = H::get_heap(&vm.state);
9191
let value = vm.state.heaps[heap].read_u256(address);
@@ -175,7 +175,7 @@ fn load_pointer<T: Tracer, W: World<T>, const INCREMENT: bool>(
175175
if pointer.offset > LAST_ADDRESS {
176176
vm.state.current_frame.pc = spontaneous_panic();
177177
return;
178-
};
178+
}
179179

180180
let start = pointer.start + pointer.offset.min(pointer.length);
181181
let end = start.saturating_add(32).min(pointer.start + pointer.length);

crates/vm2/src/precompiles/legacy.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ use primitive_types::{H160, U256};
22
use zk_evm_abstractions::{
33
aux::Timestamp,
44
precompiles::{
5+
ecadd::ecadd_function, ecmul::ecmul_function, ecpairing::ecpairing_function,
56
ecrecover::ecrecover_function, keccak256::keccak256_rounds_function,
6-
secp256r1_verify::secp256r1_verify_function, sha256::sha256_rounds_function,
7+
modexp::modexp_function, secp256r1_verify::secp256r1_verify_function,
8+
sha256::sha256_rounds_function,
79
},
810
queries::{LogQuery, MemoryQuery},
911
vm::Memory,
12+
zkevm_opcode_defs::{
13+
ECADD_PRECOMPILE_ADDRESS, ECMUL_PRECOMPILE_ADDRESS, ECPAIRING_PRECOMPILE_ADDRESS,
14+
MODEXP_PRECOMPILE_ADDRESS,
15+
},
1016
};
1117
use zkevm_opcode_defs::{
1218
PrecompileCallABI, ECRECOVER_INNER_FUNCTION_PRECOMPILE_ADDRESS,
@@ -67,7 +73,7 @@ impl Memory for LegacyIo<'_> {
6773
) -> MemoryQuery {
6874
let start_word = query.location.index.0;
6975
if query.rw_flag {
70-
assert!(start_word < 2, "standard precompiles never write >2 words");
76+
assert!(start_word < 3, "standard precompiles never write >3 words");
7177
self.output.buffer[start_word as usize] = query.value;
7278
self.output.len = self.output.len.max(start_word + 1);
7379
} else {
@@ -126,6 +132,24 @@ impl Precompiles for LegacyPrecompiles {
126132
io.output
127133
.with_cycle_stats(CycleStats::Secp256r1Verify(cycles as u32))
128134
}
135+
MODEXP_PRECOMPILE_ADDRESS => {
136+
let cycles = modexp_function::<_, false>(0, query, &mut io).0;
137+
io.output
138+
.with_cycle_stats(CycleStats::ModExp(cycles as u32))
139+
}
140+
ECADD_PRECOMPILE_ADDRESS => {
141+
let cycles = ecadd_function::<_, false>(0, query, &mut io).0;
142+
io.output.with_cycle_stats(CycleStats::EcAdd(cycles as u32))
143+
}
144+
ECMUL_PRECOMPILE_ADDRESS => {
145+
let cycles = ecmul_function::<_, false>(0, query, &mut io).0;
146+
io.output.with_cycle_stats(CycleStats::EcMul(cycles as u32))
147+
}
148+
ECPAIRING_PRECOMPILE_ADDRESS => {
149+
let cycles = ecpairing_function::<_, false>(0, query, &mut io).0;
150+
io.output
151+
.with_cycle_stats(CycleStats::EcPairing(cycles as u32))
152+
}
129153
_ => PrecompileOutput::default(),
130154
}
131155
}
@@ -311,7 +335,7 @@ mod tests {
311335

312336
prop_assert_eq!(output.len, 2);
313337
let expected_address = key_to_address(signing_key.verifying_key());
314-
let [is_success, address] = output.buffer;
338+
let [is_success, address, _] = output.buffer;
315339
if mutation.is_some() {
316340
prop_assert_ne!(address, expected_address);
317341
} else {
@@ -416,7 +440,7 @@ mod tests {
416440
LegacyPrecompiles.call_precompile(SECP256R1_VERIFY_PRECOMPILE_ADDRESS, memory, 0);
417441

418442
prop_assert_eq!(output.len, 2);
419-
let [is_ok, is_verified] = output.buffer;
443+
let [is_ok, is_verified, _] = output.buffer;
420444
if mutation.is_none() {
421445
prop_assert_eq!(is_ok, U256::one());
422446
prop_assert_eq!(is_verified, U256::one());

crates/vm2/src/precompiles/mod.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl ExactSizeIterator for PrecompileMemoryReader<'_> {
6565
/// Output of a precompile call returned from [`Precompiles::call_precompile()`].
6666
#[derive(Debug, Default)]
6767
pub struct PrecompileOutput {
68-
pub(crate) buffer: [U256; 2],
68+
pub(crate) buffer: [U256; 3],
6969
pub(crate) len: u32,
7070
pub(crate) cycle_stats: Option<CycleStats>,
7171
}
@@ -82,23 +82,34 @@ impl PrecompileOutput {
8282
impl From<U256> for PrecompileOutput {
8383
fn from(value: U256) -> Self {
8484
Self {
85-
buffer: [value, U256::zero()],
85+
buffer: [value, U256::zero(), U256::zero()],
8686
len: 1,
8787
cycle_stats: None,
8888
}
8989
}
9090
}
9191

92-
impl From<[U256; 2]> for PrecompileOutput {
93-
fn from(value: [U256; 2]) -> Self {
94-
Self {
95-
buffer: value,
96-
len: 2,
97-
cycle_stats: None,
92+
macro_rules! impl_from_array_for_precompile_output {
93+
($n:tt) => {
94+
impl From<[U256; $n]> for PrecompileOutput {
95+
fn from(value: [U256; $n]) -> Self {
96+
let mut buffer = [U256::zero(); 3];
97+
buffer[..$n].copy_from_slice(&value[..$n]);
98+
99+
Self {
100+
buffer,
101+
len: $n,
102+
cycle_stats: None,
103+
}
104+
}
98105
}
99-
}
106+
};
100107
}
101108

109+
// Implement for array sizes 2 and 3
110+
impl_from_array_for_precompile_output!(2);
111+
impl_from_array_for_precompile_output!(3);
112+
102113
/// Encapsulates precompiles used during VM execution.
103114
pub trait Precompiles {
104115
/// Calls to a precompile.

deny.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ allow = [
1818
"ISC",
1919
"Unlicense",
2020
"MPL-2.0",
21-
"Unicode-DFS-2016",
21+
"Unicode-3.0",
2222
"CC0-1.0",
2323
"BSD-2-Clause",
2424
"BSD-3-Clause",

0 commit comments

Comments
 (0)