Skip to main content

zksync_vm2/precompiles/
mod.rs

1//! Precompiles support.
2
3use primitive_types::U256;
4pub use zkevm_opcode_defs::system_params::{
5    ECRECOVER_INNER_FUNCTION_PRECOMPILE_ADDRESS, KECCAK256_ROUND_FUNCTION_PRECOMPILE_ADDRESS,
6    SECP256R1_VERIFY_PRECOMPILE_ADDRESS, SHA256_ROUND_FUNCTION_PRECOMPILE_ADDRESS,
7};
8use zksync_vm2_interface::CycleStats;
9
10pub use self::legacy::LegacyPrecompiles;
11use crate::heap::Heap;
12
13mod legacy;
14
15/// Provides access to the input memory for a precompile call.
16#[derive(Debug, Clone)]
17pub struct PrecompileMemoryReader<'a, const IN_WORDS: bool = false> {
18    heap: &'a Heap,
19    offset: u32,
20    len: u32,
21}
22
23impl<'a> PrecompileMemoryReader<'a> {
24    pub(crate) fn new(heap: &'a Heap, offset: u32, len: u32) -> Self {
25        Self { heap, offset, len }
26    }
27
28    /// Assumes that the input offset and length passed via ABI are measured in 32-byte words, rather than bytes.
29    pub fn assume_offset_in_words(self) -> PrecompileMemoryReader<'a, true> {
30        PrecompileMemoryReader {
31            heap: self.heap,
32            offset: self.offset * 32,
33            len: self.len * 32,
34        }
35    }
36}
37
38/// Iterates over input bytes.
39impl<const IN_WORDS: bool> Iterator for PrecompileMemoryReader<'_, IN_WORDS> {
40    type Item = u8;
41
42    fn next(&mut self) -> Option<Self::Item> {
43        if self.len == 0 {
44            return None;
45        }
46
47        // This assumes the offset never overflows
48        let output = self.heap.read_byte(self.offset);
49        self.offset += 1;
50        self.len -= 1;
51        Some(output)
52    }
53
54    fn size_hint(&self) -> (usize, Option<usize>) {
55        (self.len as usize, Some(self.len as usize))
56    }
57}
58
59impl ExactSizeIterator for PrecompileMemoryReader<'_> {
60    fn len(&self) -> usize {
61        self.len as usize
62    }
63}
64
65/// Output of a precompile call returned from [`Precompiles::call_precompile()`].
66#[derive(Debug, Default)]
67pub struct PrecompileOutput {
68    pub(crate) buffer: [U256; 3],
69    pub(crate) len: u32,
70    pub(crate) cycle_stats: Option<CycleStats>,
71}
72
73impl PrecompileOutput {
74    /// Assigns cycle stats for this output.
75    #[must_use]
76    pub fn with_cycle_stats(mut self, stats: CycleStats) -> Self {
77        self.cycle_stats = Some(stats);
78        self
79    }
80}
81
82impl From<U256> for PrecompileOutput {
83    fn from(value: U256) -> Self {
84        Self {
85            buffer: [value, U256::zero(), U256::zero()],
86            len: 1,
87            cycle_stats: None,
88        }
89    }
90}
91
92macro_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            }
105        }
106    };
107}
108
109// Implement for array sizes 2 and 3
110impl_from_array_for_precompile_output!(2);
111impl_from_array_for_precompile_output!(3);
112
113/// Encapsulates precompiles used during VM execution.
114pub trait Precompiles {
115    /// Calls to a precompile.
116    fn call_precompile(
117        &self,
118        address_low: u16,
119        memory: PrecompileMemoryReader<'_>,
120        aux_input: u64,
121    ) -> PrecompileOutput;
122}