Specification and Verification of Side-channel Security for Open-source Processors via Leakage Contracts

Leakage contracts have recently been proposed as a new security abstraction at the Instruction Set Architecture (ISA) level. Such contracts aim to faithfully capture the information processors may leak through side effects of their microarchitectural implementations. However, so far, we lack a verification methodology to check that a processor actually satisfies a given leakage contract. In this paper, we address this problem by developing LeaVe, the first tool for verifying register-transfer-level (RTL) processor designs against ISA-level leakage contracts. To this end, we introduce a decoupling theorem that separates security and functional correctness concerns when verifying contract satisfaction. LeaVe leverages this decoupling to make verification of contract satisfaction practical. To scale to realistic processor designs LeaVe further employs inductive reasoning on relational abstractions. Using LeaVe, we precisely characterize the side-channel security guarantees provided by three open-source RISC-V processors, thereby obtaining the first contract satisfaction proofs for RTL processor designs.


INTRODUCTION
Microarchitectural attacks [1][2][3][4][5] compromise security by exploiting software-visible artifacts of microarchitectural optimizations like caches and speculative execution.To use modern hardware securely, programmers must be aware of how these optimizations impact the security of their code.Unfortunately, instruction set architectures (ISAs), the traditional abstraction layer between hardware and software, do not provide an adequate basis for secure programming: ISAs capture the functional behavior of processors but abstract away microarchitectural details and thus fail to capture their security implications.
To build secure software systems on top of modern hardware, we need a new abstraction at the ISA level that faithfully captures the information processors may leak through their microarchitectural implementations.We refer to this new abstraction as leakage contracts.For example, the leakage contract underlying constant-time programming [6], used for writing cryptographic code, states that processors can leak a program's control flow and memory accesses, which therefore must not depend on secret data.
The proliferation of open-source processors around the RISC-V ecosystem presents an opportunity to fill this gap.
In this paper, we present the first approach for verifying registertransfer-level (RTL) processor designs against ISA-level leakage contracts.This requires overcoming the following challenges: • Bridging the abstraction gap between sequential instructionlevel leakage contracts and cycle-level processor designs that overlap the execution of multiple instructions.
• Leakage contracts capture a processor's information leakage on top of its functional specification.Verifying contract satisfaction, thus, requires reasoning about both functional and security aspects, which goes against the separation of these two concerns.
• Even simple open-source processor designs have large and complex state spaces, which prohibit explicit enumeration or bounded model checking.
Our verification approach and its implementation LeaVe overcome these challenges based on the following contributions: (1) We adapt the leakage contract framework from [7] to RTL processor designs, capturing instruction-level contracts and realistic cycle-level attacker models in a single uniform framework.
(2) We introduce a decoupling theorem that separates security and functional correctness aspects for contract satisfaction.
(3) We develop a verification algorithm for checking the security aspects of contract satisfaction that employs inductive reasoning on relational abstractions to scale to realistic processor designs.
(4) We implement and experimentally evaluate our approach on three open-source RISC-V processors.Next, we discuss these four contributions in more detail.
Leakage contracts for RTL processors: We adapt the leakage contract framework from [7] for RTL processor designs ( §3).This requires significant changes since the framework in [7] builds on top of a simple sequential operational model of an out-of-order processor rather than on cycle-level RTL circuits.In a nutshell, we model both the instruction-level leakage contract and the microarchitectural attacker as monitoring circuits.These monitoring circuits generate contract traces, capturing the processor's intended leakage at instruction level, and attacker traces, capturing its actual leakage at microarchitectural level.In this setting, a microarchitecture satisfies a contract for a given attacker if the following holds: whenever two architectural states yield different attacker traces, then the two states also yield different contract traces.
Decoupling security and functional correctness: We introduce a decoupling theorem ( §4.1) that separates security and functional correctness concerns for contract satisfaction.For this, we introduce the notion of microarchitectural contract satisfaction that refers only to the microarchitecture and ensures the absence of leaks.The decoupling theorem states that, for processors correctly implementing the instruction set architecture, contract satisfaction and microarchitectural contract satisfaction are equivalent.This allows us to focus only on the security challenges arising from leakage verification, while relying on existing approaches for functional correctness [18][19][20][21][22][23][24].
Verifying contract satisfaction: We develop a novel algorithm for checking microarchitectural contract satisfaction ( §4.2), which we prove sound.That is, whenever our algorithm concludes that a contract is satisfied, then microarchitectural contract satisfaction indeed holds.Given a contract monitoring circuit and a microarchitecture, our approach inductively learns invariants associated with pairs of microarchitectural executions with the same contract traces using invariant learning techniques [25] and uses these invariants to establish contract satisfaction.
Implementation and evaluation: We implement our approach in LeaVe, a tool for verifying microarchitectural contract satisfaction for processor designs in Verilog ( §5).We validate our approach by precisely characterizing the side-channel security guarantees of three open-source RISC-V processors in multiple configurations ( §6).For this, we define a family of leakage contracts capturing leaks through control flow, memory accesses, and variable-time instructions, and use LeaVe to determine which contracts each processor satisfies against an attacker observing when instructions retire.Our evaluation confirms that LeaVe can be used to effectively verify side-channel security guarantees provided by open-source processors in less than 25 hours for our most complex targets.Our experiments also show that checking microarchitectural contract satisfaction (as enabled by our decoupling theorem) rather than on top of an architectural reference model significantly speeds up verification (less than 2 hours versus 33 hours for a simple 2-stage processor), allowing us to scale verification to realistic processors.

Bonus material:
The LeaVe verification tool is available at [26].

OVERVIEW
Here, we illustrate the key points of our approach with an example.We start by presenting a simple instruction set and the processor implementing it ( §2.1).Next, we show how microarchitectural leaks can be formalized using leakage contracts ( §2.2).Finally, we 1 module ISA ( input clk , output register );     illustrate how the LeaVe verification tool verifies that the contract is satisfied, thereby ensuring the absence of unwanted leaks ( §2.3).

A simple processor
Next, we present the instruction set and processor implementation.Instruction set.We consider an instruction set supporting addition and multiplication of immediates to a single register.Instructions consist of the instruction type (ADD, MUL, or CLR) and an immediate value imm.ADD adds the immediate to the register value, whereas MUL multiplies the register value by the immediate.Finally, CLR resets the register to zero. Figure 1 depicts a Verilog reference model ISA for our instruction set that executes one instruction per cycle.Instructions are stored in the instruction memory imem.Lines 6 and 7 decode the instruction into operator (ADD, MUL, or CLR) and operand (immediate value).Lines 13 to 18 case-split on the type of operation and update the register with the new value.Finally, Line 10 advances the program counter.Pipelined implementation.Figure 2 shows an implementation IMPL of the instruction set that processes instructions in a threestage pipeline.If the pipeline is not stalled (flag ready), the processor starts by fetching a new instruction in line 13.As in Figure 1, the decode stage (lines 7 to 10) decodes a new instruction into operator and immediate.Next, the execute stage executes the decoded instruction (lines 24 to 34).The write-back stage updates the register with the result of the computation (lines 37 to 42).This step is controlled by the write-enabled flag we.Finally, the processor performs forwarding from the execute to the write-back stage (line 20).
Both ADD (line 27) and CLR (line 31) instructions are executed in a single cycle and their results are passed to the write-back stage.
In contrast, MUL instructions (line 29 to line 34) may take multiple cycles.Multiplication starts in line 29 by setting register mult to 1.This indicates that the processor cannot fetch new instructions (line 19) and must stall the pipeline (line 13).The processor then multiplies immediate and register value.This step is implemented in module log_time_mult (line 22), which we omit.The module takes time proportional to the logarithm of m_rd's value, i.e., the register value, to perform the multiplication. 1t also has a fast path that completes the multiplication in a single cycle whenever operand or register are 0 or 1.Once multiplication terminates, mul_res contains the multiplication result and the processor stops stalling the pipeline by setting mult to 0 (line 33) and passes the result to the write-back stage.

Specifying side-channel leakage
We now illustrate how to use leakage contracts to capture sidechannel security guarantees for our example processor.
Leakage.To use the processor from Figure 2 securely, we need to know what the processor may leak to an attacker.In the following, we consider an attacker that observes the value of the output-ready flag ready at each cycle, i.e., it observes the pipeline's timing.
Assume that initially the register has value 0. Figure 3 shows pairs of instruction sequences that an attacker can distinguish.The sequences in Figure 3a are distinguishable since the upper trace performs a multiplication while the lower trace does not, resulting in a timing difference.Similarly, the attacker can distinguish the traces in Figure 3b, as the upper trace profits from the fast path in the multiplier, while the lower trace does not.Even though the immediate operands to MUL are the same in Figure 3c, the attacker can tell the sequences apart, as the register values are different.
In contrast, Figure 4 shows pairs of instruction sequences that are indistinguishable for our attacker.Figure 4a does not leak as it does not perform multiplication.Figure 4b initially performs additions with different values, but resets the register state via CLR before MUL.Finally, Figure 4c performs additions with different values that result in the same register state before MUL.
Next, we show how to capture leakage using monitors, which we use to formalize leakage contracts and attackers.
Capturing leakage via monitors.To use the processor securely, we need to distinguish program behaviors that leak from those that do not.For this, we compose the reference model ISA (Figure 1), which captures the functional behavior of the ISA, with a leakage monitor LM shown below.The leakage monitor captures which information may be leaked upon executing instructions.The monitor takes as input a module  representing the underlying circuit.We denote by LM[] the composition of LM and  such that the composition hides 's outputs, and LM can refer to (but cannot modify) 's internal variables ( §3.3).
In our example, the monitor leaks whether the operation that is performed is a multiplication or not (ismul).Whenever a MUL is executed, the monitor additionally leaks the register value (r) and whether the immediate is 0 or 1 (isFP), thereby capturing the leaks associated with the multiplier's fast path.Note that {, , } is Verilog notation for the concatenation of signals , , and .Consider the leakage observations (i.e., the values for leak) produced by LM[ISA], i.e., the leakage monitor applied to the reference model.All pairs of sequences in Figure 4 produce the same observations, whereas all pairs in Figure 3 result in different observation traces.For example, in Figure 4a, LM[ISA] produces observations consisting of {0,0,0} for both instruction sequences.In contrast, for the second instruction of Figure 3a, the upper sequence produces observation {2,0,1} but the lower one produces {0,0,0}.
Attacker observations.Next, we define the observations an attacker can make about implementation IMPL.Since we consider an attacker that can observe the timing of the computation, we define another monitor ATK that simply exposes the ready bit.Leakage contracts.The composition LM[ISA] of leakage monitor and reference model defines a leakage contract at the ISA level.The contract characterizes leaks at the granularity of the execution of instructions from the instruction set, and it expresses which parts of the computation may be leaked by the hardware.For programmers, the contract provides a guideline for writing side-channel free code: secrets should never influence leakage observations.In our example, any two program executions that differ only in their secrets (e.g., the initial register value) must produce indistinguishable traces.4, ATK[IMPL] must produce the same sequence of ready bits.In contrast, for the pairs of sequences in Figure 3, the sequence of ready bits may differ, but it does not have to.Next, we describe our methodology to check that an implementation satisfies a contract.

Verifying contract satisfaction
Formally verifying contract satisfaction amounts to proving that LM[ISA] ⊒ ATK[IMPL] holds.This requires reasoning about pairs of infinite traces from LM[ISA] and ATK[IMPL] for all possible initial memories (including both data and instructions) and all possible initial microarchitectural states.Beyond reasoning about security, this also implicitly requires to show that IMPL correctly implements the ISA.In our example, functional correctness bugs in IMPL would often also result in contract violations as leakage observations are a function of the architectural state.For instance, assume an incorrectly implemented CLR instructions that does not reset the register to 0. Then the traces in Figure 4b would likely be distinguishable via timing.
While functional correctness is thus crucial for security, it needs to be verified independently of security concerns.Indeed, there are many existing approaches [18][19][20][21][22][23][24] for checking ISA compliance.One of the contributions of this paper is to show how leakage and functional verification can be decoupled from each other, enabling a clean separation of functional and security concerns.

ISA compliance.
So, what does it mean for the implementation to comply with the ISA? Intuitively, the implementation should go through the same sequence of architectural states as the reference model.However, the reference model processes one instruction in each cycle, while the implementation overlaps the execution of multiple instructions and may or may not retire an instruction in any given cycle.To bridge this gap, a retirement predicate captures when the processor retires instructions and thus commits changes to the architectural state.A retirement predicate  over implementation circuit IMPL must satisfy the following constraint: whenever  holds, IMPL's current architectural state corresponds to a valid architectural state of the reference model, and no changes to the architectural state may occur when  does not hold.For our example, the architectural variables are pc, imem, and register and  ≜ ( = 1) is a valid retirement predicate.In fact,  acts as a witness to the fact that IMPL complies with the ISA defined by the reference model ISA: For any initial architectural state, ISA transitions through the same sequence of architectural states as IMPL does upon instruction retirement, i.e., whenever  holds.We denote this notion of ISA compliance by IMPL ⊢  ISA.
Decoupling leakage and functional correctness.Using the retirement predicate, we are able to decouple leakage from functional verification.To this end, we first define a filtered semantics (in §3.1) that only considers states in which  holds.Since IMPL ⊢  ISA implies that IMPL's architectural state matches ISA's whenever  holds, the sequence of architectural states produced by the filtered semantics of IMPL with respect to  is equal to the sequence of states produced by ISA, assuming the processor is implemented correctly.
Based on the filtered semantics, we can define the notion of microarchitectural contract satisfaction:  following safety property: Any two prefixes of traces that agree on their leakage observations also agree on attacker observations and determine each instruction's retirement time.A challenge in this formulation is that differences in attacker observations may surface before the corresponding differences in leakage observations due to pipelined execution and the fact that leakage observations corresponding to an instruction can only be evaluated upon instruction retirement.We address this challenge by applying a bounded lookahead to the leakage observations.Checking this safety property requires appropriate inductive invariants, which would be tedious to come up with manually, in particular for complex designs.Thus, we synthesize appropriate invariants from a pool of candidate relational invariants following the classic Houdini algorithm [25].

FORMAL MODEL
In this section, we present the key components of our formal model.We start by introducing Vlog, a simple hardware description language ( §3.1).Next, we show how to formalize instruction set architectures and microarchitectures in Vlog ( §3.2).We conclude by formalizing leakage contracts ( §3.3).

𝜇Vlog: A Hardware Description Language
Vlog is a language for specifying synchronous sequential circuits.It captures the key features of hardware description languages like Verilog and VHDL, and we use it as the core language for LeaVe.
Syntax.The syntax of Vlog is given in Figure 6.Expressions  are built from values Vals = N ∪ {⊥}, which are natural numbers or the designated value ⊥, registers Regs, which store values, and variables Vars, which are shorthands for more complex expressions.Expressions can be combined using unary operators ⊖, binary operators Given a circuit , we refer to its assignments as ., to its wires as . , and to its outputs as ..The set read () of read registers consists of all registers  that occur in at least one right-hand side of an assignment in . or a wire in . .Similarly, the set write() of write registers consists of all registers  occurring in left-hand sides of assignments in ..Finally, the set wires() of wire variables consists of all variables  occurring in left-hand sides of wires in . .We assume that (1) . ⊆ vars() ∪ wires(), Semantics.We formalize the semantics of Vlog circuits by specifying how their state is updated at each cycle.We model the state of a circuit as a valuation  that maps registers in Regs to values in Vals, i.e.,  : Regs → Vals.Given a circuit , states() denotes the set of all possible valuations over vars().Given a valuation  and a set of registers  , the projection ↾  restricts the scope of  to the registers in  , i.e., ↾  () =  () for all  ∈  and ↾  () = ⊥ otherwise.Finally, given two valuations ,  ′ and a set of registers  ,  ∼   ′ denotes that  and  ′ agree on the values of all registers in  , i.e., The semantics  of a circuit  takes as input a valuation  and outputs the valuation  ′ at the next cycle.An execution for  starting from valuation  is the infinite sequence of valuations obtained by repeatedly applying  .The infinite trace semantics  ∞ of a circuit  maps each valuation  to the infinite sequence of valuations for 's outputs, where the -th valuation corresponds to the circuit's output after  cycles. 3Additionally, the filtered infinite trace semantics  ∞ | outputs only the valuations in  | that satisfy a given predicate  (other valuations are dropped).Finally,  (, ) denotes the valuation obtained by executing  for  cycles starting from valuation , whereas ,  |=  denotes that  is satisfied for circuit  and valuation .The full formalization of Vlog is given in Appendix A.
Example 2. Consider again circuit sISA from Example 1.Let us pick an initial valuation , such that  () = 0,  () = 0, and Executing a single step gives us  ′ = sISA (), with  ′ () = 1, and  ′ () = 0. Since only the program counter changed, we get  ∼ {,}  ′ , but not  ∼ { }  ′ .The trace sISA ∞ () consists of the following sequence of register values (since the register value does not change after step 11), where • denotes concatenation: As an example of filtering, consider the predicate  :=  mod 2 = 0 indicating whether the program counter is even.The filtered semantics associated with  yields the following sequence:

Modeling architectures and microarchitectures
We now show how instruction set architectures (short: architectures) and microarchitectures can be modeled in Vlog.Then, we formalize what it means for a microarchitecture Impl to correctly implement an architecture ISA.
Architectures.We view architectures as state machines that define how the execution progresses through a sequence of architectural states, where each transition corresponds to the execution of a single instruction.Given a set of architectural registers Arch, we model an architecture as a circuit ISA over Arch, i.e., vars(ISA) = ISA.= Arch.We assume that a subset init (ISA) of ISA's states are identified as initial states.
Example 3. Consider again circuit sISA from Example 1.Its variables vars(sISA) = {, , } form the architectural state of the ISA.We identify as initial states all valuations  such that  () = 0 and  () = 0.In the circuit from Figure 1 the architectural state is given by vars() = {, ,  } whereas , , and  are not listed as they are wires.
Microarchitectures.We model microarchitectures as circuits that capture the execution at the granularity of clock cycles.Thus, a microarchitecture is a circuit Impl that refers to both architectural registers in Arch and to additional microarchitectural registers Arch such that vars(Impl) = Impl.= Arch ∪ Arch and Arch ∩ Arch = ∅.We assume that a subset init (Impl) of Impl's states is identified as the initial states and require that ↾ Arch ∈ init (ISA) for any state  ∈ init (Impl), i.e., the architectural part of an initial microarchitectural state should be an initial architectural state.
Example 4. Let us look at a microarchitectural implementation sImpl of the ISA in example 1.The implementation, shown below, can be in one of two states (indicated by the register st): execute state (st = 0) or write-back state (st = 1).In the execute state, sImpl computes the result of adding the immediate to the current register value and assigns it to the variable ; it then moves to the write-back state (line 3).In the write-back state, sImpl writes the result to the register , moves the state to the execute stage, and increments the program counter (line 4).If the immediate value is zero, the implementation triggers a fast path which keeps the circuit in the execute state, increments the program counter, and leaves the register unchanged (line 2).Finally, the circuit updates the variable  which indicates whether the circuit retired in the current step.For readability, we write the example in an extended syntax that allows branches at the assignment level. 4 In addition to architectural variables {, , }, the implementation contains microarchitectural variables {, ,  }.We pick as our initial valuations all  such that  () = 0,  () = 0,  () = 0, and The predicate  characterizes when instructions are retired, i.e., when instructions modify the architectural state.Definition 1 uses  to map architectural changes made by Impl to single steps in ISA's executions.This is sufficient for single-issue processors, which retire at most one instruction per cycle.Multiple-issue processors, which may retire multiple instructions in a single cycle, require more complex ways of mapping architectural changes made by Impl to ISA's steps.To simplify our model, we decided against more complex ISA compliance criteria since LeaVe's verification approach ( §4) is decoupled from ISA compliance.
Example 5. Let's again consider implementation circuit sImpl from Example 4. We choose as retirement predicate  ≜  = 1.Let's consider again valuation  from Example 2, which maps  = 0, and  () () = , for 0 ≤  ≤ 10.Running sImpl on  from produces the following sequence of register values, where we underline a register value whenever  holds on the corresponding state.
It's easy to check that sImpl ∞ | (), i.e., the sequence of underlined values, matches sISA ∞ (), and that the register value remains unchanged whenever  doesn't hold.Since this is true, not only for  but for all valid initial states, we can conclude that sImpl correctly implements sISA, i.e., sImpl ⊢  sISA.

Leakage contracts
In this section, we first introduce monitoring circuits, which we use to specify leakage contracts and attackers.Then, we formalize contract satisfaction [7] within our modeling framework.
Monitoring circuits.Monitoring circuits monitor the behavior of another circuit, and we will use them to formalize leakage contracts and attackers.We say that circuit  is a monitoring circuit for circuit  if (1) write() ∩ write() = ∅, i.e., the two circuits write to separate sets of registers, (2) wires() ∩ wires() = ∅, i.e., the two circuits write to separate wire variables, and (3) vars() ∩ write() = ∅, i.e.,  does not influence 's behavior.Additionally,  is combinatorial whenever read () ⊆ vars(), i.e.,  only reads from  variables and thus does not have state of its own.Finally, the composition of the monitoring circuit  and the monitored circuit , written  [], is the circuit defined as . ∪ . : . ∪ . : ., which computes over 's state without changing its behavior.Leakage contracts.A leakage contract is the composition of a leakage monitor LM, i.e., a combinatorial monitoring circuit LM for the architecture ISA, with the architecture ISA itself.That is, a leakage contract LM[ISA] discloses parts of the architectural state during ISA's execution at the granularity of instruction execution.
Hardware attackers.We formalize an attacker as a combinatorial monitoring circuit Atk for the microarchitecture Impl.That is, an attacker observes parts of the microarchitecture's state during the execution at the granularity of clock cycles.Example 6.Consider again circuit sISA from Example 1, the ISA specification of our running example.We define the leakage monitor sLM, which leaks whether the current instruction is zero.As sLM only reads sISA's variables, it is combinatorial.Running sAtk[sImpl] on  yields the following sequence.
Contract satisfaction.Definition 2 formalizes the notion of contract satisfaction [7] We remark that Definition 2 refers to 4 different traces: two contract traces from LM[ISA] and two attacker traces from Atk[Impl].
Example 8. Let's consider the two pairs of memories (a) and (b) shown in Figure 7.We will check contract satisfaction, i.e., that sLM[sISA] ⊒ sAtk[sImpl] on these particular traces.
Let us start with the instructions from Figure 7a.Consider two states   and  ′  , such that   () contains the upper instructions in Figure 7, and  ′  () contains the lower ones.For  ≥ 3, we let   () =  ′  () = 0. Running   and  ′  on the contract, we get: . .As the contract traces differ in the second position, contract satisfaction holds trivially.Next, consider the traces in Figure 7b.As before, we construct valuations   for the upper trace, and  ′  for the lower trace.We get the traces below.
As both valuations produce the same trace, we need to check the attacker observations on the implementation.We get . . .We can therefore conclude that contract satisfaction holds for these traces.To verify contract satisfaction, we need to not only check this property for   and  ′  , but for any pair of traces.We will discuss our approach for this in the next section.

VERIFYING CONTRACT SATISFACTION
Here, we present our verification approach for checking contract satisfaction.First, we introduce a decoupling theorem that allows us to separate security and functional correctness proofs ( §4.1).Next, we present (and prove sound) an algorithm for verifying microarchitectural contract satisfaction ( §4.2).All proofs are in Appendix C.

Decoupling contract satisfaction from ISA
Since a leakage contract LM[ISA] is defined on top of ISA, proving contract satisfaction according to Definition 2 requires reasoning about security and functional compliance with respect to ISA (since one needs to map contract traces from LM[ISA] to implementation traces).We address this challenge by decoupling reasoning about security and about ISA compliance.
Leakage ordering.For this, we start by introducing a leakage ordering between combinatorial monitoring circuits for an underlying circuit .Intuitively, a monitor  for  "leaks less" (i.e., exposes less information) than another monitor  ′ for  if whenever  ′ [] produces equivalent traces on two initial states, then  [] also produces equivalent traces.Definition 3 formalizes this concept and extends it to support the filtered semantics.Definition 3. Monitor  ′ leaks at most as much information as monitor  about circuit , given registers  ⊆ vars(), and predicate  (over ), written  ⪰ Differently from Definition 2 (which is defined in terms of four traces), Definition 3 is defined in terms of only two traces of .
Example 9. We can use our new definition to express contract satisfaction over the implementation only, using predicate .Consider again the two pairs of traces in Figure 7 from Example 8.If we assume that the implementation is functionally correct, that is, it satisfies Definition 1, we can replace the specification sISA by its implementation sImpl.In particular, since Definition 1 ensures that sISA's architectural values match sImpl's whenever retirement predicate  = ( = 1) holds, we can check contract satisfaction by checking sLM ⪰ {st,res,ret }, sImpl sAtk.We call this condition microarchitectural contract satisfaction.Let us now check this property for the traces in Figure 7b.Running sLM[sImpl], we get the following, where we underline outputs whenever  holds.
This means the premise of the implication is satisfied, and we need to check the conclusion.As before, we get which establishes sLM ⪰ {st,res,ret }, sImpl sAtk for   and  ′  .We formalize this idea in Theorem 1.
Decoupling theorem.Theorem 1 states that, for functionally correct processors, microarchitectural contract satisfaction (i.e., LM ⪰ Arch, Impl Atk, which only refers to the microarchitecture Impl), is equivalent to contract satisfaction (Definition 2 which refers to architecture ISA and microarchitecture Impl).This allows us to cleanly separate reasoning about security and about functional correctness (without losing precision).In particular, we can split proving contract satisfaction into proving microarchitectural contract satisfaction (which ensures the absence of leaks with respect to Impl) and ISA compliance.LeaVe leverages Theorem 1 to only reason about security, whereas ISA compliance can be verified separately using techniques focusing on functional correctness [18].

Verifying microarchitectural contract satisfaction
In this section, we present an algorithm for checking microarchitectural contract satisfaction, i.e., LM ⪰ Arch, Impl Atk.We first introduce notation for formalizing our verification queries in terms of temporal logic formulas.Next, we present the verification algorithm and conclude by proving its soundness.
Notation.To formalize our verification queries, we use a linear temporal logic over Vlog circuits.Formulas Φ in this logic are constructed by combining Vlog predicates  with temporal operators • (denoting "in the next cycle"), □  (denoting "for the next  cycles"), and □ (denoting "always in the future"), and the usual boolean operators.Given a temporal formula Φ over a circuit , we write , ,  |= Φ to denote that the formula is satisfied for initial state  at cycle .We write ,  |= Φ to mean , , 0 |= Φ, and  |= Φ to mean that ,  |= Φ holds for all .Our temporal logic is standard; we provide its formalization in Appendix B.
Product circuit.Verifying microarchitectural contract satisfaction requires us to reason about pairs of executions of Impl, i.e., it is a 2-hyperproperty [29].We transform hyperproperties into properties over a single execution using a construction called selfcomposition [30].For this, we construct a product circuit that executes two copies of a circuit  ( 1 and  2 ) in parallel.Given circuit Stuttering product circuit.While the product circuit allows us to reason about pairs of executions, we need another ingredient to check microarchitectural contract satisfaction, as it refers to the filtered semantics over a predicate .We cannot directly check the filtered semantics on the product circuit, as  may be satisfied at different times.Instead, we modify the product circuit to synchronize the two executions based on .Given a circuit  = { 1 ←  1 , . . .,   ←   } : { 1 =  ′ 1 , . . .,   =  ′  } :  1 , . . .,   , we define its stuttering product circuit over predicate , denoted by  ×  , by replacing each assignment  1 ←  1 in the product circuit  ×  with  1 ← if  1 ∧ ¬ 2 th  1 el  1 and, similarly, by replacing each  2 ←  2 in the product circuit  ×  with  2 ← if  2 ∧ ¬ 1 th  2 el  2 .This transformation ensures that whenever  holds in one execution but not the other, the execution where  holds "waits" for the other one to catch up.
We can now check properties of the filtered semantics, e.g., that Algorithm idea.We now use the stuttering product circuit to verify that LM ⪰ Arch, Impl Atk holds.This requires us to show that all executions whose filtered semantics produce the same contract observations always produce the same attacker observations (see Definition 3).We start by adding an assumption to only consider executions of Impl ×  Impl that are contract equivalent.We encode this via the formula Φ ctr −equiv := ( 1 ∧  2 →  LM equiv ), where  M equiv :=  ∈ . 1 =  2 for a monitor .We then only consider executions that satisfy □Φ ctr −equiv .Next, our algorithm learns an inductive invariant LI over the stuttering product circuit under our assumption.This invariant holds on all reachable states of the circuit.Finally, our algorithm uses the invariant to prove that indeed all executions of the circuit are attacker equivalent.For this we show that LI →  Atk equiv holds.Note that we prove this property over Impl ×  Impl, however the consequent of LI →  Atk equiv is stated over the unfiltered semantics.To ensure that the stuttering semantics is equivalent to the regular one, we also prove LI → ( 1 ↔  2 ), i.e., no stuttering occurs on contract equivalent traces.
Algorithm description.We implement this approach in Algorithm 1.It relies on the procedure LearnInv, which we use to learn invariants over the stuttering product circuit.We first present Verify and later discuss LearnInv.
Function Verify is the entry point of our verification approach.It takes as input a Vlog microarchitecture Impl (the processor under verification), a leakage monitor LM (capturing the allowed leaks), an attacker monitor Atk (capturing what the attacker can observe), and a retirement predicate .To verify unbounded properties like LM ⪰ Arch, Impl Atk, the algorithm relies on inductive reasoning.For this reason, Verify additionally take as input (1) a set of candidate invariants CI over the stuttering circuit (which will be verified using LearnInv) as well as (2) a lookahead  ∈ N + .Concretely, LeaVe constructs the set of candidate invariants CI directly from Impl, Atk, and ; see §5 for more details.
In line 2, we construct Φ initial (over the stuttering circuit Impl ×  Impl) capturing the initial conditions for pairs of executions relevant to our check.In Φ initial ,  Impl init 1 and  Impl init 2 capture that the two executions start from valid initial states, whereas  Arch equiv ensures that the two executions initially agree on all registers in Arch, i.e.,  Arch equiv :=  ∈Arch  1 =  2 .In line 3, we construct Φ ctr −equiv := ( 1 ∧  2 →  LM equiv ) ensuring that contract observations are equivalent.In line 4, we call the LearnInv procedure to verify which of the candidate invariants in CI are, indeed, invariants.Hence, the learned invariants LI hold for any two contract-indistinguishable executions, i.e.,  |= (Φ initial ∧ □Φ ctr −equiv ) → □  holds where  stands for  ∈ .Finally, in line 5 we check whether the learned invariants are sufficient to ensure that (1) the attacker observations are the same and (2) the predicate  is always synchronized between the two executions.If this is the case, Verify has successfully verified that LM ⪰ Arch, Impl Atk holds; see Theorem 2. The LearnInv procedure learns, using inductive verification, which of the candidate invariants are true invariants using an approach similar to the Houdini tool [25].LearnInv takes as input a circuit , a formula capturing initial conditions Φ initial , a formula Φ assumption that executions always need to satisfy, a bound , and a set of candidate invariants  .The procedure outputs the formulas in  that can be proved to be invariants, i.e., for which  |= (Φ initial ∧ □Φ  ) → □  holds.Concretely, Learn-Inv consists of a base case (lines 7-13) and an induction step (lines 14-20).Both parts follow a similar structure-they iteratively rule out invalid invariants based on counterexamples-and they differ only in the checked property: Ψ base checks that for any state for which the initial conditions hold and for which the assumptions are satisfied for the next  cycles, the invariants must also hold.In contrast, Ψ induction checks that for any state for which the invariants hold and for which the assumptions are satisfied for the next  cycles, the invariants hold in the next cycle as well.Bound  controls for how many cycles to unroll the assumption □Φ  .Unrolling the assumption is important for circuits where a difference in attacker observation occurs before a corresponding difference in contract observations.This may happen, e.g., if a leak occurs early in the pipeline and is later justified by a difference in contract observations at retirement.It therefore often suffices to bound  by the processor's pipeline depth.
Soundness: Theorem 2 states that whenever Algorithm 1 returns ⊤, then microarchitectural contract satisfaction holds.Example 12. Consider again the implementation sImpl from Example 4. We want to verify that sLM ⪰ {st,res,ret }, sImpl sAtk holds.We start by building the stuttering product circuit sImpl ×  sImpl with respect to retirement predicate  = ( = 1).We can assume that the two executions produce the same contract observations, whenever both executions retire.We capture this assumption in formula ), which we assume to hold throughout the execution.Next, we want to learn an inductive invariant over sImpl ×  sImpl under assumption □ Φ ctr −equiv .We pick the following set of candidate invariants.
Procedure LearnInv starts by checking the invariant candidates on the initial state.We set bound  to 1. Since in all valid initial states , we have  () = 1,  () = 0, and all microarchitectural variables Φ ctr −equiv := ( 1 ∧  2 →  LM equiv ) 4: := LearnInv(Impl ×  Impl, Φ initial , Φ ctr −equiv , ,  ) 6: procedure LearnInv(, Φ initial , Φ assumption , ,  ) 7: while ⊤ do ⊲ base case 8: if  |= Ψ base then Let  be the counterexample Let  be the counterexample 20: are assumed to be equal via Φ initial we retain all candidate invariants.Next, LearnInv checks whether the candidate invariants are preserved under transitions.That is, if we assume the invariant holds and take a transition step, the invariant must still hold.Since our invariant does not require memory  to be equal in both executions, taking the else branch in line 3 of sImpl (see Example 4) produces a counterexample where  1 ≠  2 and we remove the corresponding invariant.Similarly, taking the else branch in line 3 produces a state where  1 = 1 and  1 = 0 and LearnInv removes the invariant as well.The remaining candidate invariants are preserved under transitions and the procedure returns.This leaves us with the following set of learned invariants.
Finally, procedure Verify checks whether the conjunction of the learned invariants implies that attacker observations and retirement are the same in both executions.For our example, this means checking that the following implication holds.
As the implication is valid, we have proved microarchitectural contract satisfaction.

IMPLEMENTATION
In this section, we present the LeaVe verification tool, which implements the verification approach from §4.2 for Verilog.LeaVe uses the Yosys Open Synthesis Suite [31] for processing Verilog circuits, the Icarus Verilog simulator [32] for simulating counterexamples, and the Yices SMT solver [33] for verification.LeaVe is open source and available at [26] together with the benchmarks and scripts for reproducing the experiments from §6.
Inputs: LeaVe takes as input (1) the processor under verification (PUV) Impl implemented in Verilog, (2) a leakage monitor formalized as Verilog expressions over Impl's architectural state, (3) an attacker expressed as Verilog expressions over Impl, (4) a retirement predicate  expressed as a Boolean condition over Impl, and (5) a lookahead  ∈ N + . 6Users can provide candidate relational invariants as expressions  over Impl and LeaVe will construct the candidate invariant  1 =  2 .Users can also provide additional invariants over individual executions of Impl to help ruling out spurious counterexamples. 7orkflow: LeaVe works in two steps that follows Algorithm 1. First, LeaVe determines the greatest subset of the provided candidate relational invariants that is inductive.For this, LeaVe implements the LearnInv function from Algorithm 1 (described below).In addition to the user provided candidate invariants, the set of candidate invariants for LearnInv contains: (1) all relational formulas of the form  1 =  2 where  is a register or wire in Impl, (2) formulas of the form  Atk 1 =  Atk 2 for all expressions  Atk in the provided attacker, and (3) the invariant  1 ↔  2 indicating that the retirement predicate is always synchronized between the two executions.
Next, LeaVe analyzes the learned invariants to determine if they are sufficient to prove security with respect to the given attacker.For this, LeaVe checks if the invariants associated with the attacker and with the retirement predicate are part of the set of learned invariants, which is sufficient to ensure the satisfaction of the check at line 5 in Algorithm 1.
Implementation of LearnInv: LeaVe's implementation of LearnInv follows Algorithm 1: (1) It constructs the stuttering product circuit by combining two copies of the PUV and using the provided retired predicate  to synchronize the two executions (as described in §4.2). ( 2) Then, it inlines the property to be verified (i.e., Ψ base and Ψ inductive from Algorithm 1) as assume and assert Verilog statements in the product circuit.(3) Next, it checks whether the property holds.(4) Whenever a property is not satisfied, LeaVe analyzes the counterexample to determine which candidate relational invariants are violated (lines 12-13 and 19-20 in Algorithm 1) For ( 1) and ( 2), we implemented dedicated Yosys passes that construct the stuttering product circuit and inline candidate relational invariants.For (3), LeaVe uses Yosys to encode the product circuit and the verification queries into SMT logical formulas and the Yosys-BMC [31] backend to verify the property with the Yices SMT solver (using the lookahead  as verification bound).For (4), when verification fails, Yosys-BMC translates the SMT counterexample into a Verilog testbench.LeaVe instruments the testbench to monitor the value of all candidate invariants, simulates the testbench using Icarus Verilog, and discards the violated invariants.This section reports on our use of LeaVe to verify the security of three open-source RISC-V processors.We start by introducing our methodology ( §6.1): the processors we analyze, the leakage contracts and attacker we consider, and the experimental setup.In our experimental evaluation ( §6.2), we address the following three research questions: Q1: Can LeaVe be used to reason about the security of open-source RISC-V processors?Q2: What is the impact of varying the lookahead  on verification time?Q3: What is the impact of decoupling security and functional correctness on verification?

Methodology
Benchmarks: We consider the following benchmarks.
• RE: The simple processor from §2.The log_time_mul module is implemented using shift operations (logarithmic in the number of set bits of the multiplier), inspired by one of Ibex's multipliers [28].
• Sodor: An educational RISC-V processor [35].We analyzed the 2-stage version of Sodor implementing the RV32I instruction set.
• Ibex: An open-source, production-quality 32-bit RISC-V CPU core [36]. 8We target Ibex in its default configuration (called "small" [36]), which underwent functional correctness verification.The processor has two stages and supports the RV32IMC instruction set.In our experiments, we consider three variants of Ibex: (1) Ibex-small is the default "small" configuration with constant-time multiplication (three cycles) and without caches, (2) Ibex-cache is the Ibex-small version extended with a simple (single-line) cache, and (3) Ibex-mult-div employs a non-constant-time multiplication unit whose execution time depends on the operands [28].
For the RISC-V processors in our experiments (i.e., all variants of DarkRISCV, Sodor, Ibex), we make the following assumptions during verification: (1) debug mode is disabled, (2) all fetched instructions are legal and not compressed, (3) no exceptions or interrupts are raised during execution, and (4) only unprivileged instructions are executed.Additionally, for Ibex-cache, we assume that memory operations are aligned at word boundaries due to limitations of our simple cache implementation.Finally, for all processors we manually specify a retirement predicate indicating when instructions retire.
Leakage contracts: We consider leakage contracts constructed by composing the following building blocks: • I: This contract exposes the architectural program counter and the corresponding instruction retrieved from memory.
• B: This contract exposes the architectural outcome of (direct and indirect) branch instructions.That is, for conditional branches, the contract exposes the architectural value of the condition.
• M: This contract exposes the addresses accessed by load and store memory instructions.
• A: This contract exposes whether load and store memory instructions are aligned.
• O m : This contract exposes the operands of mul and imul multiplication instructions.
• O d : This contract exposes whether the divisor in div (division) and rem (remainder) instructions is 0. In the following, we write A+B to denote the composition of contracts A and B. For instance, I+B+M is the contract that exposes everything exposed by I, B, and M.This contract corresponds to the standard constant-time model [6].We order contracts by the amount of information they leak, where stronger contracts leak less.For example, I is stronger than I+B as it exposes less information.For each processor from §6.1, we implemented all the above mentioned contracts and their combinations as leakage monitors over the processor's architectural state.
Attacker: For all processors from §6.1, we implemented an attacker monitor that observes when instructions retire by exposing the value of the retirement predicate at each cycle.
Additional candidate invariants: For DarkRISCV, Sodor, and Ibex, we manually specified candidate relational invariants capturing that "if instructions enter a pipeline stage in both executions, then the instructions are the same in both executions".Moreover, for Ibex-cache, we also added a candidate invariant capturing that "if both executions are executing a load instruction, then the signals detecting a cache hit are the same."All these invariants can be formalized as formulas of the form  1 =  2 →  ′1 =  ′2 .These are not part of the invariants automatically generated by LeaVe, which are of the simpler form  1 =  2 .
Experimental setup: All our experiments are run on a Ubuntu 20.04 virtual machine with 8 CPU cores and 32 GB of RAM running on Linux KVM on a server with 4 Xeon Gold 6154 CPUs and 512 GB of DDR4 RAM.We configured LeaVe to run with Yosys version 0.24 + 10, Icarus Verilog version 12.0, and Yices version 2.6.4.

Experimental results
Q1: Reasoning about open-source processors: To evaluate whether LeaVe can verify the security guarantees of open-source processors, we use it to prove microarchitectural contract satisfaction against an attacker Atk that observes when instructions are retired.For each processor and leakage monitor from §6.1, we use LeaVe to check whether the attacker monitor leaks less than the leakage monitor with respect to the processor and its retirement predicate (indicating whenever instructions retire).
Table 1 reports (1) the strongest contract that could be verified against Atk, (2) the time needed for the verification of the satisfaction of the strongest contract, (3) the total number of iterations taken by LearnInv for the base and induction steps (i.e., the number of issued SMT queries), and (4) the minimum lookahead  for which verification succeeded.We highlight the following findings: • For the RE processor from §2, LeaVe successfully verified contract satisfaction against the contract O m exposing the multiplication's operand in 1.5 minutes with a lookahead of 33.Such a lookahead is needed to ensure that in-flight multiplications are retired and the corresponding contract observation is produced.
• For DarkRISCV, LeaVe proves contract satisfaction against the I contract, which exposes the current program counter and the • Differently from DarkRISCV, Sodor-2 only satisfies the weaker I+B contract, which additionally exposes the outcome of branch instructions.This arises from the processor employing a simple form of branch prediction, which predicts that the branch is always not taken.This results in a timing leak because mispredictions trigger a pipeline flush.Consider the following instruction (returned by LeaVe as a counterexample when trying to prove satisfaction against I)  ≜ beq  1  2 pc + 4 at address pc, which conditionally jumps to pc + 4 if registers  1 and  2 have the same value.The next instruction will always be the one at address pc+4 (so, executions will be equivalent under contract I).However, executing  on Sodor-2 takes a different number of cycles depending on whether  1 and  2 are equal.
• For Ibex-small, LeaVe can only prove security against the I+B+O d +A contract, which additionally exposes (a) whether the divisor in division and remainder instructions is 0 and (b) whether memory accesses are aligned.The O d is needed to capture that division and remainder operations take 1 cycle when the divisor is 0 or 37 cycles otherwise.Moreover, the A contract is needed to capture that Ibex handles memory accesses that are not aligned on word boundaries by performing two separate word-aligned memory accesses.Note that the difference in complexity between Sodor-2 (a simple educational processor) and Ibex-small (a productionquality processor) is reflected in the difference in the time taken by a single LearnInv iteration (1.1 versus 16 minutes on average) and by the larger lookahead (1 vs 38).
• For Ibex-cache, LeaVe can only prove security against the I+B+O d +M contract.Differently from Ibex-small, which is secure against the I+B+O d +A contract, Ibex-cache needs the M contract that exposes the accessed memory addresses (rather than the alignment bit).This reflects the effects of our single-line cache which requires 3 cycles for hits and 4 cycles for misses.
• For Ibex-mult-div, LeaVe can only prove security against the I+B+O d +O m +A contract, which also exposes the operands of multiplication instructions (O m ).This captures the effects of the non-constant-time multiplier used in Ibex-mult-div, whose execution time is proportional to the logarithm of the multiplication operands.2 reports the total verification time, the total number of iterations taken by the LearnInv sub-procedure for the base and induction steps (i.e., the number of issued SMT queries), the time per iteration, and the number of invariants learned.Our results indicate that increasing the lookahead  results in slower iterations of LearnInv and in more invariants.For instance, increasing the bound from 1 to 20 results in increasing the iteration time from 1.15 to 8.29 minutes.The total number of LearnInv iterations (and, thus, the total verification time), however, varies depending on which counterexamples the SMT solver returns.
Q3: Impact of decoupling: To understand the impact of checking microarchitectural contract satisfaction using our decoupling theorem versus checking contract satisfaction directly using an architectural model ISA (c.f.Definition 2), we modified LeaVe to directly prove contract satisfaction according to Definition 2. For this, we (1) replace the construction of the stuttering circuit Impl ×  Impl with the product circuit ISA × ISA × Impl × Impl and (2) modify the construction of the Ψ initial and Ψ contract formulae, whereas the rest (e.g., the LearnInv procedure) is the same.We refer to this modified version of LeaVe as 4way-LeaVe (see Algorithm 2 in appendix).Note that 4way-LeaVe and LeaVe prove different properties which, as stated in Theorem 2, are equivalent only for ISA-compliant designs.
We analyzed the Sodor processor against the I+B contract using both LeaVe and 4way-LeaVe.We focused our analysis on Sodor because it comes with a Verilog ISA model (i.e., 1-stage Sodor).
In our experiments, when using a lookahead of  = 2, LeaVe successfully proved that the I+B contract is satisfied in 97.8 minutes.In contrast, 4way-LeaVe tool proved contract satisfaction in 33.5 hours.This illustrates that, even for the simple 2-stage Sodor processor, directly proving Definition 2 is impractical.It also confirms that our decoupling theorem is instrumental in enabling practical automated proofs of contract satisfaction for realistic hardware.

DISCUSSION
Limitations: Our formalization of leakage contracts and our notion of ISA compliance impact both the decoupling theorem (Theorem 1) as well as the microarchitectures and contracts supported by LeaVe.In terms of microarchitectures, our notion of ISA compliance (Definition 1) only applies to single-issue processors.Supporting multi-issue processors requires an ISA compliance notion that accounts for retiring multiple instructions per cycle.In terms of leakage contracts, LeaVe targets sequential leakage contracts that only refer to "architectural" instructions.We leave the support for leakage contracts that refer to transient instructions, like the speculative contracts from [7], as future work.
We also remark that (1) LeaVe currently lacks support for inputs, and (2) our formalization of attackers as combinatorial monitoring circuits limits LeaVe to reason about passive attackers that can only observe (part of) a processor's microarchitecture during execution.We leave corresponding extensions to future work.
Lookahead: LeaVe's verification approach is parametric in a lookahead  ∈ N + which determines for how many cycles the contract-equivalence assumption needs to be unrolled in the verification queries issued by the LearnInv function in Algorithm 1.The lookahead  is used to expose contract observations (produced at retirement) for instructions that are in-flight.In particular, it allows accounting for microarchitectural differences at cycle  that are later declassified by a contract observation produced at cycle (at most)  + .We remark that the choice of  does not affect the soundness of LeaVe (cf.Theorem 2), but it may affect the success of verification.For instance, verifying the satisfaction of the contract LM from §2 for the processor from Figure 2 requires  = 33 (see Table 1), i.e., verification fails for smaller bounds.In our experiments, setting  to the maximum number of cycles needed for instructions to traverse the pipeline (from fetch to retire) was always sufficient whenever contract satisfaction holds.
Leakage contracts and secure programming: Leakage contracts may serve as a foundation for secure programming.As shown by Guarnieri et al. [7], ensuring at program level that secret data do not influence leakage contract traces is sufficient to ensure the absence of leaks at microarchitectural level for processors that satisfy the contract.Thus, LeaVe's verification results have direct implications for programmers.As an example, for each processor in our evaluation ( §6), the strongest contract verified by LeaVe, reported in Table 1, indicates which parts of a computation should not involve secrets to ensure leakage freedom.For instance, secure programming for the contract I+B+O d +O m +A, satisfied by Ibexmult-div, requires ensuring that secrets do not influence (i) the program's control-flow (I+B), (ii) whether the divisor in div and rem instructions is 0 (O d ), (iii) the operands of mul and imul instructions (O m ), and (iv) the alignment of memory accesses (A).

RELATED WORK
Hardware verification for security: UPEC [37] is an approach for detecting confidentiality violations in RTL circuits.Similarly to Definition 3, the UPEC property is defined as a non-interference-style property over pairs of microarchitectural executions.However, the security property verified in [37] is fixed; it specifically focuses on microarchitectural leaks due to transitive execution; and it is not directly based on an ISA-level specification, i.e., it does not correspond to a leakage contract in a straightforward manner.In contrast, our approach directly supports leakage contracts defined at ISA-level.
Bloem et al. [38] propose an approach for verifying power leakage models (formalized on top of the Sail domain specific language [39]) for RTL circuits, which differs from LeaVe in two key ways: (1) They target power side channels, whereas LeaVe focuses on software-visible microarchitectural leaks.This is reflected in different notions of contract satisfaction: the one from [38] is probabilistic and related to threshold non-interference, whereas ours is related to standard non-interference.(2) Their verification approach needs a user-provided simulation mapping that "specifies for all registers in the hardware [..] a location in the contract modeling the hardware location" [38, §3.4]where a location is a register or an input.Defining such a mapping can be challenging for complex processors, e.g., registers of stateful microarchitectural components (like caches or predictors) may depend on multiple instructions.LeaVe does not need such a mapping for checking contract satisfaction; it only needs (automatically synthesized or manually provided) candidate relational invariants over the microarchitecture.
Iodine [40] and Xenon [41] check if the execution time of an RTL circuit is input independent given a partitioning of the circuit's inputs into secret and public.This partitioning is too coarse to support leakage contracts, where the notion of what is "secret" depends on the executed instructions.Finally, secure Hardware Description Languages [42,43] aim at building secure processors by construction.They require partitioning RTL registers and inputs into secret and public, which is too coarse-grained for leakage contracts.
Knox [44] is a verification approach for hardware security modules (HSMs) that targets an HSM's hardware and software components.While leakage contracts capture a processor's security guarantees at ISA level, Knox focuses on ensuring that all components of an HSM are both functionally correct and leakage free.Differently from LeaVe, Knox relies on a combination of annotations and interactive proofs.
Hardware verification for functional correctness: A multitude of approaches for verifying functional correctness of processors have been proposed [18][19][20][21][22][23][24].Some of these approaches adopt a notion of ISA compliance similar to Definition 1.For instance, Reid et al. [18] illustrate a verification approach (used internally at ARM) for checking compliance between a microarchitecture and a reference architectural model, where the notion of ISA compliance requires that all changes to the architectural state are reflected by a "step" of the reference model (similarly to Definition 1).
The Instruction-Level Abstraction (ILA) project [19,20,45] aims to specify and verify instruction-level models of processors and accelerators.They present techniques for (1) checking whether an RTL implementation correctly implements an ILA model, (2) determining which parts of a processor's state are architectural [20], and (3) deriving processor invariants [45].Some of these techniques can help in LeaVe's verification.For instance, [20] can help in identifying the Arch and Arch sets, whereas [45] can complement LeaVe's invariant learning approach.
Finally, fuzzing approaches [46,47] can detect violations of ISA compliance, but they cannot prove functional correctness.
Detecting leaks through testing: Revizor [14,15] and Scam-V [16,17] search for contract violations (i.e., they find counterexamples to Definition 2) for black-box CPUs.However, they require physical access to a CPU and can be applied only post-silicon.Other approaches [48][49][50] instead detect leaks by analyzing hardware measurements without the help of a formal leakage model but, again, apply only post-silicon.Finally, SpecDoctor [51] and SigFuzz [52] can test for leaks on RTL designs and they are applicable in the pre-silicon phase.Differently from LeaVe, all these approaches cannot prove the absence of leaks.
Formal leakage models: Researchers have proposed many formal models for studying microarchitectural security at program level, ranging from simple models associated with "constant-time programming" [6,53] to more complex ones capturing leaks associated with speculatively executed instructions [9][10][11][12][13]54].Most of these models focus at the software level and have no formal connection with leaks in hardware implementations.In contrast, [7,8] propose frameworks for formalizing security contracts between hardware and software.Our notion of contract satisfaction (Definition 2) is inspired by the framework from [7], which we instantiate and adapt for reasoning about RTL processors.

CONCLUSION
We presented an approach for verifying RTL processor designs against ISA-level leakage contracts.We implemented our approach in the LeaVe verification tool, which we use to characterize the sidechannel security guarantees of three open-source RISC-V processors.This demonstrates that leakage contracts can be successfully applied to RTL processor designs.It also paves the way for linking recent advances on specification [7,8] and software analysis [9][10][11][12][13] for leakage contracts to RTL processor designs.

B A TEMPORAL LOGIC FOR 𝜇Vlog
Here, we introduce a logic for expressing temporal properties of Vlog circuits.Formulas Φ in this logic are constructed by combining Vlog predicates  with temporal operators • (denoting "in the next cycle"), □  (denoting "for the next  cycles"), □ (denoting "always in the future"), and the usual boolean operators.Its semantics is the following: Proof.We assume Impl ⊢  ISA and prove the two directions.⇒: Let ,  ′ ∈ init (Impl) be such that  ∼ Arch  ′ and LM[ISA] ∞ () = LM[ISA] ∞ ( ′ ).
Since Impl ⊢  ISA and LM is a monitoring circuit for ISA, we get

Figure 4 :
Figure 4: Traces that do not leak via timing.

1 4 end
monitor ATK ( module M , output leak ) 2 always @ ( * ) begin 3 leak = M .ready ;The composition of attacker and implementation ATK[IMPL] defines the actual information an attacker may learn about the implementation.
and bitselection operators  1 [ 2 :  3 ].An assignment  ←  sets the next value of register  to the value of expression  in the current cycle.A wire  =  always has the value of expression .Finally, a circuit  consists of a set of assignments , a set of wires  , and a set of outputs  ⊆ Regs ∪ Vars.

Figure 6 :Example 1 .
Figure 6: Vlog syntax where vars() = read () ∪ write(), (2) each register and variable is on the left-hand side of at most one assignment or wire, and (3) wires in . do not introduce cyclic dependencies.Example 1.Consider the circuit sISA given below.The circuit implements a simple ISA, in which instructions consist solely of immediate values [] that are retrieved from memory  and added to the single internal register . 2 sISA = { ←  + 1,  ←  + []} : {} : {} We have vars(sISA) = read (sISA) = {, , } and write(sISA) = {, }, and the single output ; the circuit satisfies our assumptions.

Figure 7 :
Figure 7: Two pairs of instruction traces.

𝑒 1 [𝑒 2 :Figure 8 :
Figure 8: Vlog semantics.A Vlog SEMANTICSThe full semantics of Vlog is given in Figure8.In the figure,  denotes the empty sequence and • denotes the concatenation operator.As is standard, we have that  •  =  and  •  = .As mentioned in §3.1, the trace semantics extends the notion of valuation to refer to both registers and wire variables in a circuit's output as shown in the definition of the projection ↾  ().

Contract satisfaction. The implementation IMPL satisfies the contract LM[ISA] under the attacker ATK whenever IMPL leaks no more than specified by the contract under ATK. That is, cir- cuit ATK[IMPL] should leak no more than circuit LM
To this end, we apply the leakage monitor LM directly to IMPL and then relate LM[IMPL] to ATK[IMPL], bypassing the reference model: For all pairs of traces of LM[IMPL], if contract observations (filtered using ) are the same, then ATK[IMPL]'s observations must also be the same.We denote this relation by LM ⪰ . Intuitively, a microarchitecture Impl satisfies the contract LM[ISA] for an attacker Atk if Atk cannot learn more information about the initial architectural state by monitoring Impl's executions than what is exposed by LM[ISA].That is, for any two initial states that agree on their microarchitectural part 5 , whenever LM[ISA] results in identical traces, then Atk[Impl] also results in identical traces (i.e., Atk cannot distinguish the two initial architectural states).Microarchitecture Impl satisfies contract LM[ISA] for attacker Atk, written LM[ISA] ⊒ Atk[Impl], if for all valuations ,  ′ Theorem 1 (Decoupling Theorem).If Impl ⊢  ISA holds for retirement predicate , then Algorithm 1 LeaVe verification approach Input: Microarchitecture Impl, leakage monitor LM, attacker Atk, retirement predicate , lookahead , candidate invariants 1: procedure Verify(Impl, LM, Atk, , ,  ) 2:

Table 1 :
Verification results for our benchmarks.For each processor, the table indicates the strongest satisfied contract (i.e., the one exposing the least amount of information) against an attacker observing when instructions retire.