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

Commit

Permalink
Remove bootstrapping (0xPolygonZero#1390)
Browse files Browse the repository at this point in the history
* Start removing bootstrapping

* Change the constraint for kernel code initializing

* Update specs

* Apply comments

* Add new global metadata to circuit methods

* Change zero-initializing constraint

* Apply comment

* Update circuit size range for recursive test
  • Loading branch information
hratoanina authored Nov 30, 2023
1 parent 471ff68 commit 30c944f
Show file tree
Hide file tree
Showing 19 changed files with 150 additions and 296 deletions.
12 changes: 4 additions & 8 deletions evm/spec/tables/cpu.tex
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ \subsection{CPU}

\subsubsection{CPU flow}

An execution run can be decomposed into three distinct parts:
An execution run can be decomposed into two distinct parts:
\begin{itemize}
\item \textbf{Bootstrapping:} The CPU starts by writing all the kernel code to memory and then hashes it. The hash is then compared to a public value shared with
the verifier to ensure that the kernel code is correct.
\item \textbf{CPU cycles:} The bulk of the execution. In each row, the CPU reads the current code at the program counter (PC) address, and executes it. The current code can be the kernel code,
or whichever code is being executed in the current context (transaction code or contract code). Executing an instruction consists in modifying the registers, possibly
performing some memory operations, and updating the PC.
\item \textbf{Padding:} At the end of the execution, we need to pad the length of the CPU trace to the next power of two. When the program counter reaches the special halting label
\item \textbf{Padding:} At the end of the execution, we need to pad the length of the CPU trace to the next power of two. When the program counter reaches the special halting label
in the kernel, execution halts. Constraints ensure that every subsequent row is a padding row and that execution cannot resume.
\end{itemize}

Expand All @@ -26,22 +24,20 @@ \subsubsection{CPU flow}
\subsubsection{CPU columns}

\paragraph*{Registers:} \begin{itemize}
\item \texttt{is\_bootstrap\_kernel}: Boolean indicating whether this is a bootstrapping row or not. It must be 1 at the first row, then switch to 0 until the end.
\item \texttt{context}: Indicates which context we are in. 0 for the kernel, and a positive integer for every user context. Incremented by 1 at every call.
\item \texttt{code\_context}: Indicates in which context the code to execute resides. It's equal to \texttt{context} in user mode, but is always 0 in kernel mode.
\item \texttt{program\_counter}: The address of the instruction to be read and executed.
\item \texttt{stack\_len}: The current length of the stack.
\item \texttt{is\_kernel\_mode}: Boolean indicating whether we are in kernel (i.e. privileged) mode. This means we are executing kernel code, and we have access to
privileged instructions.
\item \texttt{gas}: The current amount of gas used in the current context. It is eventually checked to be below the current gas limit. Must fit in 32 bits.
\item \texttt{is\_keccak\_sponge}: Boolean indicating whether we are executing a Keccak hash. This happens whenever a \texttt{KECCAK\_GENERAL} instruction is executed, or at the last
cycle of bootstrapping to hash the kernel code.
\item \texttt{is\_keccak\_sponge}: Boolean indicating whether we are executing a Keccak hash. Only used as a filter for CTLs.
\item \texttt{clock}: Monotonic counter which starts at 0 and is incremented by 1 at each row. Used to enforce correct ordering of memory accesses.
\item \texttt{opcode\_bits}: 8 boolean columns, which are the bit decomposition of the opcode being read at the current PC.
\end{itemize}

\paragraph*{Operation flags:} Boolean flags. During CPU cycles phase, each row executes a single instruction, which sets one and only one operation flag. No flag is set during
bootstrapping and padding. The decoding constraints ensure that the flag set corresponds to the opcode being read.
padding. The decoding constraints ensure that the flag set corresponds to the opcode being read.
There isn't a 1-to-1 correspondance between instructions and flags. For efficiency, the same flag can be set by different, unrelated instructions (e.g. \texttt{eq\_iszero}, which represents
the \texttt{EQ} and the \texttt{ISZERO} instructions). When there is a need to differentiate them in constraints, we filter them with their respective opcode: since the first bit of \texttt{EQ}'s opcode
(resp. \texttt{ISZERO}'s opcode) is 0 (resp. 1), we can filter a constraint for an EQ instruction with \texttt{eq\_iszero * (1 - opcode\_bits[0])}
Expand Down
16 changes: 13 additions & 3 deletions evm/spec/tables/memory.tex
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ \subsection{Memory}
The memory table should be ordered by $(a, \tau)$. Note that the correctness of the memory could be checked as follows:
\begin{enumerate}
\item Verify the ordering by checking that $(a_i, \tau_i) \leq (a_{i+1}, \tau_{i+1})$ for each consecutive pair.
\item Enumerate the purportedly-ordered log while tracking the ``current'' value of $v$, which is initially zero.\footnote{EVM memory is zero-initialized.}
\item Enumerate the purportedly-ordered log while tracking the ``current'' value of $v$.
\begin{enumerate}
\item Upon observing an address which doesn't match that of the previous row, if the operation is a read, check that $v = 0$.
\item Upon observing an address which doesn't match that of the previous row, if the address is zero-initialized
and if the operation is a read, check that $v = 0$.
\item Upon observing a write, don't constrain $v$.
\item Upon observing a read at timestamp $\tau_i$ which isn't the first operation at this address, check that $v_i = v_{i-1}$.
\end{enumerate}
Expand Down Expand Up @@ -64,6 +65,15 @@ \subsubsection{Timestamps}
Note that it doesn't mean that all memory operations have unique timestamps. There are two exceptions:

\begin{itemize}
\item Before bootstrapping, we write some global metadata in memory. These extra operations are done at timestamp $\tau = 0$.
\item Before the CPU cycles, we write some global metadata in memory. These extra operations are done at timestamp $\tau = 0$.
\item Some tables other than CPU can generate memory operations, like KeccakSponge. When this happens, these operations all have the timestamp of the CPU row of the instruction which invoked the table (for KeccakSponge, KECCAK\_GENERAL).
\end{itemize}

\subsubsection{Memory initialization}

By default, all memory is zero-initialized. However, to save numerous writes, we allow some specific segments to be initialized with arbitrary values.

\begin{itemize}
\item The read-only kernel code (in segment 0, context 0) is initialized with its correct values. It's checked by hashing the segment and verifying
that the hash value matches a verifier-provided one.
\end{itemize}
Binary file modified evm/spec/zkevm.pdf
Binary file not shown.
225 changes: 0 additions & 225 deletions evm/src/cpu/bootstrap_kernel.rs

This file was deleted.

3 changes: 0 additions & 3 deletions evm/src/cpu/columns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ pub(crate) struct PartialMemoryChannelView<T: Copy> {
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub(crate) struct CpuColumnsView<T: Copy> {
/// Filter. 1 if the row is part of bootstrapping the kernel code, 0 otherwise.
pub is_bootstrap_kernel: T,

/// If CPU cycle: Current context.
pub context: T,

Expand Down
5 changes: 2 additions & 3 deletions evm/src/cpu/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub(crate) fn eval_packed_generic<P: PackedField>(
let is_cpu_cycle: P = COL_MAP.op.iter().map(|&col_i| lv[col_i]).sum();
let is_cpu_cycle_next: P = COL_MAP.op.iter().map(|&col_i| nv[col_i]).sum();

let next_halt_state = P::ONES - nv.is_bootstrap_kernel - is_cpu_cycle_next;
let next_halt_state = P::ONES - is_cpu_cycle_next;

// Once we start executing instructions, then we continue until the end of the table
// or we reach dummy padding rows. This, along with the constraints on the first row,
Expand Down Expand Up @@ -94,8 +94,7 @@ pub(crate) fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
let is_cpu_cycle = builder.add_many_extension(COL_MAP.op.iter().map(|&col_i| lv[col_i]));
let is_cpu_cycle_next = builder.add_many_extension(COL_MAP.op.iter().map(|&col_i| nv[col_i]));

let next_halt_state = builder.add_extension(nv.is_bootstrap_kernel, is_cpu_cycle_next);
let next_halt_state = builder.sub_extension(one, next_halt_state);
let next_halt_state = builder.sub_extension(one, is_cpu_cycle_next);

// Once we start executing instructions, then we continue until the end of the table
// or we reach dummy padding rows. This, along with the constraints on the first row,
Expand Down
Loading

0 comments on commit 30c944f

Please sign in to comment.