# Output-sensitive information flow analysis *

Cristian Ene, Laurent Mounier, Marie-Laure Potet

► To cite this version:

Cristian Ene, Laurent Mounier, Marie-Laure Potet. Output-sensitive information flow analysis *. Logical Methods in Computer Science, 2021, 17 (1), pp.15:1-15:29. 10.23638/LMCS-17(1:15)2021. hal-04750655

HAL Id: hal-04750655

https://hal.science/hal-04750655v1

Submitted on 23 Oct 2024

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_1.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
# OUTPUT-SENSITIVE INFORMATION FLOW ANALYSIS *

CRISTIAN ENE, LAURENT MOUNIER, AND MARIE-LAURE POTET

Univ. Grenoble Alpes, CNRS, Grenoble INP, VERIMAG, 38000 Grenoble, France

*e-mail address:* Cristian.Ene@univ-grenoble-alpes.fr

*e-mail address:* Laurent.Mounier@univ-grenoble-alpes.fr

*e-mail address:* Marie-Laure.Potet@univ-grenoble-alpes.fr

**ABSTRACT.** *Constant-time* programming is a countermeasure to prevent cache based attacks where programs should not perform memory accesses that depend on secrets. In some cases this policy can be safely relaxed if one can prove that the program does not leak more information than the public outputs of the computation.

We propose a novel approach for verifying constant-time programming based on a new information flow property, called *output-sensitive noninterference*. Noninterference states that a public observer cannot learn anything about the private data. Since real systems need to intentionally declassify some information, this property is too strong in practice. In order to take into account public outputs we proceed as follows: instead of using complex explicit declassification policies, we partition variables in three sets: input, output and leakage variables. Then, we propose a typing system to statically check that leakage variables do not leak more information about the secret inputs than the public normal output. The novelty of our approach is that we track the dependence of leakage variables with respect not only to the initial values of input variables (as in classical approaches for noninterference), but taking also into account the final values of output variables. We adapted this approach to LLVM IR and we developed a prototype to verify LLVM implementations.

## 1. INTRODUCTION

An important task of cryptographic research is to verify cryptographic implementations for security flaws, in particular to avoid so-called timing attacks. Such attacks consist in measuring the execution time of an implementation on its execution platform. For instance, Brumley and Boneh [12] showed that it was possible to mount remote timing attacks by against OpenSSL's implementation of the RSA decryption operation and to recover the key. Albrecht and Paterson [3] showed that the two levels of protection offered against the Lucky 13 attack from [2] in the first release of the new implementation of TLS were imperfect. A related class of attacks are *cache-based attacks* in which a malicious party is able to obtain memory-access addresses of the target program which may depend on secret data through observing cache accesses. Such attacks allow to recover the complete AES keys [17].

*Key words and phrases:* Information flow, Output-sensitive non-interference, Type system.

<figure><img src="image_2.png" /></figure>

<footnote>* This work is supported by the French National Research Agency in the framework of the “Investissements d’avenir” program (ANR-15-IDEX-02).</footnote>
A possible countermeasure is to follow a very strict programming discipline called **constant-time programming**. Its principle is to avoid branchings **controlled** by secret data and memory load/store operations **indexed** by secret data. Recent secure C libraries such as NaCl [10] or mbedTLS<fnref n="1" /> follow this programming discipline. Until recently, there was no rigorous proof that constant-time algorithms are protected against cache-based attacks. Moreover, many cryptographic implementations such as PolarSSL AES, DES, and RC4 make array accesses that depend on secret keys and are not constant time. Recent works [6, 4, 11] fill this gap and develop the first formal analyzes that allow to verify if programs are correct with respect to the constant-time paradigm.

An interesting extension was brought by Almeida et al. [4] who enriched the constant-time paradigm “distinguishing not only between public and private input values, but also between private and publicly observable output values”. This distinction raises interesting technical and theoretical challenges. Indeed, constant-time implementations in cryptographic libraries like OpenSSL include optimizations for which paths and addresses can depend not only on public input values, but also on publicly observable output values. Hence, considering only input values as non-secret information would thus incorrectly characterize those implementations as non-constant-time. [4] also develops a verification technique based on *symbolic execution*. However, the soundness of their approach depends in practice on the soundness of the underlying symbolic execution engine, which is very difficult to guarantee for real-world programs with loops. Moreover, their product construction can be very expensive in the worst case.

In this paper we deal with *statically checking programs* for **output-sensitive constant-time** correctness: programs can still do branchings or memory accesses controlled by secret data if the information that is leaked is subsumed by the normal output of the program. To give more intuition about the property that we want to deal with, let us consider the following example, where *ct_eq* is a constant time function that allows to compare the arguments:

```c
good = 1;
i = 0;

for ( ; i<B_Size; i++){
    good = good & ct_eq(secret[i], in_p[i]);
}

if (!good) {
    i = 0;
    for ( ; i<B_Size; i++) secret[i] = 0;
}

return good;
```

Let suppose that the array variable *secret* is secret, and all the other variables are public. Intuitively this a sort of one-time check password verifying that *in_p* = *secret* and otherwise overwrites the array *secret* with zero. Obviously, this function is not constant-time as the variable *good* depends on *secret*, and hence branching on *good* violates the principles of constant-time programming. It is easy to transform this program into an equivalent one which is constant time. For example one could replace

```c
if (!good) {
```

<footnote n="1">¹mbed TLS (formerly known as PolarSSL). https://tls.mbed.org/</footnote>
```c
    i = 0;
    for ( ; i<B_Size; i++) secret[i] = 0;
}
```

by

```c
    i = 0;
    for ( ; i<B_Size; i++) {
        secret[i] = secret[i] & ct_eq(good, 1);
    }
```

But branching on *good* is a benign optimization, since anyway, the value of *good* is the normal output of the program. Hence, even if the function is not constant-time, it should be considered **output-sensitive constant time** with respect to its specification. Such optimization opportunities arise whenever the interface of the target application specifies what are the publicly observable outputs, and this information is sufficient to classify the extra leakage as benign [4].

The objective of this work is to propose a *static method* to check if a program is **output-sensitive side-channel secure**. We emphasize that our goal is **not** to verify that the legal output leaks “too much”, but rather to ensure that the unintended (side-channel) output does not leak **more than** this legal output.

First, we propose a novel approach for verifying *constant-time like security* based on a new information flow property, called *output-sensitive noninterference*. Information-flow security prevents confidential information to be leaked to public channels. Noninterference states that a public observer cannot learn anything about the private data. Since real systems need to intentionally declassify some information, this property is too strong. A possible alternative is *relaxed noninterference* which allows to specify explicit *downgrading policies*. For instance, in [27], the authors proposed the “delimited release security property” that captures the leakage by a “declassify” primitive, which allows to state *explicitly* what is permitted to be leaked with respect to the *initial state*.

In order to take into account public outputs while staying independent of how programs intentionally declassify information, we develop an alternative solution: instead of using complex explicit policies for functions, we partition variables in three sets: input, output and *leakage variables*. Hence we distinguish between the legal public output and the information that can leak through side-channels, expressed by adding fresh additional leakage variables. Then we propose a typing system that can statically check that leakage variables do not leak more secret information than the **public normal output**. Therefore, in our case, the legal leakage is *implicitly* defined by the normal output of the program and not by any dedicated language primitive. The novelty of our approach is that we track the dependence of leakage variables with respect to both the *initial value of input variables* (as classically the case for noninterference) and *final values of output variables*, which hardens the analysis.

As an application of this new non-interference property, we show how to verify that a program written in a high-level language is output-sensitive constant time secure by using this typing system.

Since timed and cache-based attacks target the executions of programs, it is important to carry out this verification in a language close to the machine-executed assembly code. Hence, we adapt our approach to a generic unstructured assembly language inspired from LLVM and we show how we can verify programs coded in LLVM. Finally, we developed
a prototype tool implementing our type system and we show how it can be used to verify
LLVM implementations.

To summarize, this work makes the following contributions described above:

* in section 2 we reformulate output-sensitive constant-time as a new interesting noninterference property and we provide a sound type system that guarantees that well-typed programs are output-sensitive noninterferent;

* in section 3 we show that this general approach can be used to verify that programs written in a high-level language are output-sensitive constant time;

* in section 4 we adapt our approach to the LLVM-IR language and we develop a prototype tool that can be used to verify LLVM implementations.

## 2. OUTPUT-SENSITIVE NON-INTERFERENCE

In this section we introduce *output-sensitive noninterference* as a new information flow
property that aims to extend classical noninterference definitions in two directions:

* this property should be able to characterize *general side channel attacks*;

* in the same time, it should be accurate enough to capture the precise side channel information leaked *beyond* the regular output of the program.

In order to take into account public outputs while staying independent of how programs intentionally declassify information, we partition variables in three sets: input, output and *leakage variables*. Hence we distinguish between the legal public output and the information that can leak through side-channels, expressed by adding fresh additional leakage variables. These leakage variables are updated each time that some information is leaked to the environment. For instance, for some leakage variable $x_l$, if an adversary can get some knowledge about the branch that will be taken in case of a test condition *if e then c₁ else c₂*, we update $x_l$ with a dependency on *e*. Similarly, for some assignment $x := f(e₁, ..., e_n)$, if the evaluation of *f* is time-dependent on its arguments, then we update $x_l$ with dependencies on $e₁, ..., e_n$. In this paper we focus on constant-time security, but our approach could be used as well for other side-channel attacks.

In order to precisely characterize the side channel information leaked additionally with
respect to the normal output of the program, we also consider *output variables*.

The novelty of our approach is that we track the dependency of leakage variables with
respect to both the *initial value of input variables* (as classically the case for noninterference)
and *final values of output variables*, which hardens the analysis.

The rest of the section is structured as follows: first we introduce the *While* language and we formulate the definition of output-sensitive noninterference. Then we propose a typing system that can statically check that leakage variables do not leak more secret information than the public normal output. We conclude the section by proving the soundness of this typing system.

### 2.1. The While language and Output-sensitive noninterference.
In order to reason about the security of the code, we first develop our framework in *While*, a simple high-level structured programming language. In section 3 we shall enrich this simple language with
$$
\begin{array}{c}
\frac{
  \frac{(x := e, \sigma) \rightarrow \sigma[x \mapsto \sigma(e)]}{(\text{skip}, \sigma) \rightarrow \sigma}
}{
  \frac{(c_1, \sigma) \rightarrow \sigma'}{(c_1; c_2, \sigma) \rightarrow (c_2, \sigma')}
}
\frac{
  \frac{\sigma(e) = 1 \ ? \ i = 1 \ : \ i = 2}{(\text{If } e \text{ then } c_1 \text{ else } c_2 \text{ fi, } \sigma) \rightarrow (c_i, \sigma)}
}{
  (\text{While } e \text{ Do } c \text{ oD, } \sigma) \rightarrow (\text{If } e \text{ then } c \text{; While } e \text{ Do } c \text{ oD else skip fi, } \sigma)
}
\end{array}
$$

<caption>Figure 1: Operational semantics of the While language</caption>

arrays and in section 4 we adapt our approach to a generic unstructured assembly language.
The syntax of While programs is listed below:

$$
c ::= x := e \mid \mathit{skip} \mid c_1; c_2 \mid \mathit{If } e \mathit{ then } c_1 \mathit{ else } c_2 \mathit{ fi} \mid \mathit{While } e \mathit{ Do } c \mathit{ oD}
$$

Meta-variables *x*, *e* and *c* range over the sets of program variables *Var*, expressions and programs, respectively. We leave the syntax of expressions unspecified, but we assume they are deterministic and side-effect free. The semantics is shown in Figure 1. The reflexive and transitive closure of $\rightarrow$ is denoted by $\implies$. A state $\sigma$ maps variables to values, and we write $\sigma(e)$ to denote the value of expression *e* in state $\sigma$. A configuration $(c, \sigma)$ is a program *c* to be executed along with the current state $\sigma$. Intuitively, if we want to model the security of some program *c* with respect to side-channel attacks, we can assume that there are three special subsets of variables: $X_I$ the public input variables, $X_O$ the public output variables and $X_L$ the variables that leak information to some malicious adversary. Then, output sensitive noninterference asks that every two complete executions starting with $X_I$-equivalent states and ending with $X_O$-equivalent final states must be indistinguishable with respect to the leakage variables $X_L$. In the next definition, $=X$ relates two states that coincide on all variables belonging to $X$.

**Definition 2.1** (adapted from [4]). Let $X_I, X_O, X_L \subseteq Var$ be three sets of variables, intended to represent the input, the output and the leakage of a program. A program *c* is (*X_I*, *X_O*, *X_L*)-output-sensitive non-interferent when all its executions starting with *X_I*-equivalent stores and leading to *X_O*-equivalent final stores, give *X_L*-equivalent final stores. Formally, for all $\sigma, \sigma', \rho, \rho'$, if $\langle c, \sigma \rangle \implies \sigma'$ and $\langle c, \rho \rangle \implies \rho'$ and $\sigma =_{X_I} \rho$ and $\sigma' =_{X_O} \rho'$, then $\sigma' =_{X_L} \rho'$.

**Example 2.2.** To illustrate the usefulness of the output-sensitive non-interference property let us consider again the example given in the previous section, shown on Figure 2. Then, in order to reduce its output-sensitive constant time security to the output-sensitive non-interference property (as in Definition 2.1), first, we add a fresh variable **xl** to accumulate the leakage information (using the abstract concatenation operator **@**). Then, variable **xl** is updated with the boolean condition of each branching instruction (i.e., at lines 3, 7, 9, 12 and 16) and with each expression used as an index array (i.e., at lines 5 and 14). The result of this transformation is given on Figure 3 (we denote by **ct_eq_ni** the function obtained by applying recursively the same transformation to **ct_eq**). We consider the following sets of variables: $X_I = \{\mathit{in\_p}\}$, $X_L = \{\mathbf{xl}\}$ and $X_O = \{\mathit{good}\}$. One can check that, for each pair of
1 good = 1;
2 i = 0;
3 **for** (; i<B Size; i++){
4 good = good & ct_eq(secret[i], in_p[i]);
5 }
6 **if** (!good) {
7 i = 0;
8 **for** (; i<B Size; i++) {
9 secret[i] = 0;
10 }
11 **return** good;

<caption>Figure 2: C code example from Section 1</caption>

1 good = 1;
2 i = 0;
3 xl = xl @ (i<B Size);
4 **for** (; i<B Size; i++){
5 xl = xl @ i;
6 good = good & ct_eq_ni(secret[i], in_p[i]);
7 xl = xl @ (i<B Size);
8 }
9 xl = xl @ good;
10 **if** (!good) {
11 i = 0;
12 xl = xl @ (i<B Size);
13 **for** (; i<B Size; i++) {
14 xl = xl @ i;
15 secret[i] = 0;
16 xl = xl @ (i<B Size);
17 }
18 }
19 **return** good;

<caption>Figure 3: C code example from Section 1 with explicit leakage</caption>

executions starting with the same value of *in_p* and ending with the same value of *good*, then the final value of *xl* will be the same. Then, according to Definition 2.1, this program is (*X*<sub>*I*</sub>, *X*<sub>*O*</sub>, *X*<sub>*L*</sub>)-output-sensitive non-interferent.

In Section 3 we will show that this transformation is general and, moreover, whenever
the transformed program satisfies Definition 2.1, then the initial program is output-sensitive
constant-time, i.e., it can still do branchings or memory accesses controlled by secret data
if the information that is leaked is subsumed by its normal output. Note that the code of
Figure 3 is a simplified application of this transformation to the code of Figure 2, i.e., we omitted trivial assignments of the form $x1 = x1$.

## 2.2. Preliminary definitions and notations.
As usual, we consider a flow lattice of security types $\mathcal{L}$ (also called security levels). An element $x$ of $\mathcal{L}$ is an atom if $x \neq \perp$ and there exists no element $y \in \mathcal{L}$ such that $\perp \sqsubseteq y \sqsubseteq x$. A lattice is called **atomistic** if every element $x \in \mathcal{L}$ is the join of the set of atoms below it [25]. This set is denoted by $At(x)$.

**Assumption 2.3.** Let $(\mathcal{L}, \sqcap, \sqcup, \perp, \top)$ be an atomistic bounded lattice. As usual, we denote $t_1 \sqsubseteq t_2$ iff $t_2 = t_1 \sqcup t_2$. We assume that there exists a distinguished subset $\mathcal{T}_O \subseteq \mathcal{L}$ of atoms. Hence, from the above assumption, for any $\tau_o, \tau'_o \in \mathcal{T}_O$ and for any $t_1, t_2 \in \mathcal{L}$: it holds that

$$ (A1) \quad \tau_o \sqsubseteq \tau'_o \text{ implies } \tau_o = \tau'_o, $$

$$ (A2) \quad \tau_o \sqsubseteq t_1 \sqcup t_2 \text{ implies } \tau_o \sqsubseteq t_1 \text{ or } \tau_o \sqsubseteq t_2, $$

$$ (A3) \quad \tau_o \sqsubseteq t_1 \text{ implies that there exists } t \in \mathcal{L} \text{ such that } t_1 = t \sqcup \tau_o \text{ and } \tau_o \not\sqsubseteq t. $$

The assumption that our set $\mathcal{L}$ of security types is an atomistic lattice provides a general structure which is sufficient for our purposes: it ensures the existence of decompositions in atoms for any element in the lattice, and the ability to syntactically replace an atomic type by another (not necessarily atomic) type.

A type environment $\Gamma : Var \mapsto \mathcal{L}$ describes the **security levels** of variables and the dependency with respect to the **current** values of variables in $X_O$. In order to catch dependencies with respect to current values of output variables, we associate to each output variable $o \in X_O$ a fixed and unique symbolic type $\alpha(o) \in \mathcal{T}_O$. For example if some variable $x \in Var$ has the type $\Gamma(x) = Low \sqcup \alpha(o)$, it means that the value of $x$ depends only on public input and the current value of the output variable $o \in X_O$.

Hence, we assume that there is a fixed injective mapping $\alpha : X_0 \mapsto \mathcal{T}_0$ such that
$$ \bigwedge_{o_1, o_2 \in X_O} (o_1 \neq o_2 \Rightarrow \alpha(o_1) \neq \alpha(o_2)) \wedge \bigwedge_{o \in X_O} (\alpha(o) \in \mathcal{T}_O). $$
We extend mappings $\Gamma$ and $\alpha$ to sets of variables in the usual way: given $A \subseteq Var$ and $B \subseteq X_O$ we note $\Gamma(A) \stackrel{def}{=} \bigsqcup_{x \in A} \Gamma(x)$,

$$ \alpha(B) \stackrel{def}{=} \bigsqcup_{x \in B} \alpha(x). $$

Our type system aims to satisfy the following output sensitive non-interference condition: if the final values of output variables in $X_O$ remain the same, only changes to initial inputs with types $\sqsubseteq t$ should be visible to leakage outputs with type $\sqsubseteq t \sqcup \alpha(X_O)$. More precisely, given a derivation $\vdash_{\alpha} \Gamma\{c\}\Gamma'$, the final value of a variable $x$ with final type $\Gamma'(x) = t \sqcup \alpha(A)$ for some $t \in \mathcal{L}$ and $A \subseteq X_O$ should depend at most on the initial values of those variables $y$ with initial types $\Gamma(y) \sqsubseteq t$ and on the final values of variables in $A$. We call “real dependencies” the dependencies with respect to initial values of variables and “symbolic dependencies” the dependencies with respect to the current values of output variables. Following [19] we formalize the non-interference condition satisfied by the typing system using reflexive and symmetric relations.

We write $=_{A_0}$ for relation which relates mappings which are equal on all values in $A_0$ i.e. for two mappings $f_1, f_2 : A \mapsto B$ and $A_0 \subseteq A$, $f_1 =_{A_0} f_2$ iff $\forall a \in A_0, f_1(a) = f_2(a)$. For any mappings $f_1 : A_1 \mapsto B$ and $f_2 : A_2 \mapsto B$, we write $f_1[f_2]$ the operation which updates
$f_1$ according to $f_2$, namely

$$f_1[f_2](x) \stackrel{\text{def}}{=} \begin{cases} f_2(x) & \text{if } x \in A_1 \cap A_2 \\ f_1(x) & \text{if } x \in A_1 \setminus A_2 \end{cases}$$

Given $\Gamma: Var \to \mathcal{L}$, $X \subseteq Var$ and $t \in \mathcal{L}$, we write $=_{\Gamma,X,t}$ for the reflexive and symmetric relation which relates states that are equal on all variables having type $v \subseteq t$ in environment $\Gamma$, provided that they are equal on all variables in $X$: $\sigma =_{\Gamma,X,t} \sigma'$ iff $\sigma =_{X} \sigma' \Rightarrow (\forall x, (\Gamma(x) \subseteq t \Rightarrow \sigma(x) = \sigma'(x)))$. When $X = \emptyset$, we omit it, hence we write $=_{\Gamma,t}$ instead of $=_{\Gamma,\emptyset,t}$.

**Definition 2.4** [20]. Let $\mathcal{R}$ and $\mathcal{S}$ be reflexive and symmetric relations on states. We say that program $c$ maps $\mathcal{R}$ into $\mathcal{S}$, written $c: \mathcal{R} \implies \mathcal{S}$, iff $\forall \sigma, \rho$, if $\langle c, \sigma \rangle \implies \sigma'$ and $\langle c, \rho \rangle \implies \rho'$ then $\sigma \mathcal{R} \rho \Rightarrow \sigma' \mathcal{S} \rho'$.

The type system we propose enjoys the following useful property:

$$\text{if } \vdash_{\alpha} \Gamma\{c\}\Gamma' \text{ then } c :=_{\Gamma, \Gamma(X_I)} \implies :=_{\Gamma', X_O, \alpha(X_O) \sqcup \Gamma(X_I)}$$

This property is an immediate consequence of Theorem 2.17.

Hence, in order to prove that the above program $c$ is output sensitive non-interferent according to Definition 2.1, it is enough to check that for all $x_l \in X_L$, $\Gamma'(x_l) \subseteq \alpha(X_O) \sqcup \Gamma(X_I)$. Two executions of the program $c$ starting from initial states that coincide on input variables $X_I$, and ending in final states that coincide on output variables $X_O$, will coincide also on the leaking variables $X_L$.

We now formally introduce our typing system. Due to assignments, values and types of variables change dynamically. For example let us assume that at some point during the execution, the value of $x$ depends on the initial value of some variable $y$ and the current value of some output variable $o$ (which itself depends on the initial value of some variable $h$), formally captured by an environment $\Gamma$ where $\Gamma(o) = \Gamma_0(h)$ and $\Gamma(x) = \Gamma_0(y) \sqcup \alpha(o)$, where $\Gamma_0$ represents the initial environment. If the next to be executed instruction is some assignment to $o$, then the current value of $o$ will change, so we have to mirror this in the new type of $x$: even if the value of $x$ does not change, its new type will be $\Gamma'(x) = \Gamma_0(y) \sqcup \Gamma_0(h)$ (assuming that $\alpha(o) \not\subseteq \Gamma_0(y)$). Hence $\Gamma'(x)$ is obtained by replacing in $\Gamma(x)$ the symbolic dependency $\alpha(o)$ with the real dependency $\Gamma(o)$. The following definition formalizes this operation that allows to replace an atom $t^0$ by another type $t'$ in a type $t$ (seen as the join of the atoms of its decomposition).

**Definition 2.5.** If $t^0 \in \mathcal{T}_O$ is an atom and $t', t \in \mathcal{L}$ are arbitrary types, then we denote by $t[t'/t^0]$ the type obtained by replacing (if any) the occurrence of $t^0$ by $t'$ in the decomposition $At(t)$ in atoms of $t$

$$t[t'/t^0] \stackrel{\text{def}}{=} \begin{cases} t & \text{if } t^0 \notin At(t) \\ t' \sqcup \sqcup_{b \in At(t) \setminus \{t^0\}} b & \text{if } t^0 \in At(t) \end{cases}$$

Now we extend this definition to environments: let $x \in X_O$ and $p \in \mathcal{L}$. Then $\Gamma_1 \stackrel{\text{def}}{=} \Gamma \triangleleft_{\alpha} x$ represents the environment where the symbolic dependency on the last value of $x$ of all variables is replaced by the real type of $x$: $\Gamma_1(y) \stackrel{\text{def}}{=} (\Gamma(y))[\Gamma(x)/\alpha(x)]$. Similarly, $(p, \Gamma) \triangleleft_{\alpha} x \stackrel{\text{def}}{=} p[\Gamma(x)/\alpha(x)]$.
2.3. **Useful basic lemmas.** The following lemma is an immediate consequence of the Assumption 2.3 and Definition 2.5.

**Lemma 2.6.** Let $x \in X_O, p \in \mathcal{L}$ and let us denote $\Gamma_1 \stackrel{def}{=}} \Gamma \triangleleft_\alpha x$ and $p_1 \stackrel{def}{=}} (p, \Gamma) \triangleleft_\alpha x$. If $\alpha(x) \not\sqsubseteq \Gamma(x)$, then,

(1) For any $v \in X$, $\Gamma_1(v) = (\Gamma(v), \Gamma) \triangleleft_\alpha x$,

(2) For all variables $y \in Var$, $\alpha(x) \not\sqsubseteq \Gamma_1(y)$.

(3) $\alpha(x) \not\sqsubseteq p_1$.

We want now to extend the above definition from a single output variable $x$ to subsets $X \subseteq X_O$. Our typing system will ensure that each generated environment $\Gamma$ will not contain circular symbolic dependencies between output variables, i.e., there are no output variable $o_1, o_2 \in X_O$ such that $\alpha(o_1) \sqsubseteq \Gamma(o_2)$ and $\alpha(o_2) \sqsubseteq \Gamma(o_1)$. We can associate a graph $G(\Gamma) = (X_O, E)$ to an environment $\Gamma$, such that $(o_1, o_2) \in E$ iff $\alpha(o_1) \sqsubseteq \Gamma(o_2)$. We say that $\Gamma$ is **well formed**, denoted $WF(\Gamma)$, if $G(\Gamma)$ is an acyclic graph. For acyclic graphs $G(\Gamma)$, we define a preorder over $X_O$, denoted $\sqsubseteq_\Gamma$, as the transitive closure of the relation $\{(o_1, o_2) \in X_O \times X_O \mid \alpha(o_1) \sqsubseteq \Gamma(o_2)\}$, i.e. $o_1 \sqsubseteq_\Gamma o_2$ iff there is a path from $o_1$ to $o_2$ in $G(\Gamma)$. We also define the reachable variables of $x \in X_O$ w.r.t. $\Gamma$, denoted $GT_\Gamma(x)$, to be the set of all $o \in X_O$ such that $x \sqsubseteq_\Gamma o$. Now, for acyclic graphs $G(\Gamma)$, we can extend Definition 2.5 to subsets $X \subseteq X_O$, by first fixing an ordering $X = \{x_1, x_2, \dots, x_n\}$ of variables in $X_O$ compatible with the graph (i.e. $j \le k$ implies that $x_j \not\sqsubseteq_\Gamma x_k$), and then $(p, \Gamma) \triangleleft_\alpha X \stackrel{def}{=}} (((p, \Gamma) \triangleleft_\alpha x_1) \triangleleft_\alpha x_2) \dots \triangleleft_\alpha x_n$. We also denote $\Gamma \triangleleft_\alpha X \stackrel{def}{=}} ((\Gamma \triangleleft_\alpha x_1) \triangleleft_\alpha x_2) \dots \triangleleft_\alpha x_n$ (in this case the ordering is not important, i.e. $(\Gamma \triangleleft_\alpha x_1) \triangleleft_\alpha x_2 = (\Gamma \triangleleft_\alpha x_2) \triangleleft_\alpha x_1$).

The following lemma can be proved by induction on the size of $X$ using Lemma 2.6.

**Lemma 2.7.** Let $X \subseteq X_O, p \in \mathcal{L}$ and let us denote $\Gamma_2 \stackrel{def}{=}} \Gamma \triangleleft_\alpha X$ and $p_2 \stackrel{def}{=}} (p, \Gamma) \triangleleft_\alpha X$. If $WF(\Gamma)$, then,

(1) For any $v \in X$, $\Gamma_2(v) = (\Gamma(v), \Gamma) \triangleleft_\alpha X$,

(2) For all variables $x \in X$, and all variables $y \in Var$, $\alpha(x) \not\sqsubseteq \Gamma_2(y)$.

(3) For all variables $x \in X$, $\alpha(x) \not\sqsubseteq p_2$.

Next Lemma gives a precise characterization of the new preorder induced by the application of the operator $\triangleleft_\alpha$.

**Lemma 2.8.** Let $\Gamma$ be a well formed environment and let $x \in X_O$ and $X \subseteq X_O$. Let us denote $\Gamma_1 \stackrel{def}{=}} \Gamma \triangleleft_\alpha x$ and $\Gamma_2 \stackrel{def}{=}} \Gamma \triangleleft_\alpha X$. Then $\Gamma_1$ and $\Gamma_2$ are well formed. Moreover, $\sqsubseteq_{\Gamma_1} = \sqsubseteq_{\Gamma} \setminus \{(x, o) \mid o \in X_O\}$ and $\sqsubseteq_{\Gamma_2} = \sqsubseteq_{\Gamma} \setminus \{(x, o) \mid x \in X, o \in X_O\}$.

*Proof.* The key remark is that any edge of $G(\Gamma_1)$ where $\Gamma_1 \stackrel{def}{=}} \Gamma \triangleleft_\alpha x$ corresponds to either an edge or to a path of length two in $G(\Gamma)$. Indeed, let $x_1, x_2 \in X_O$ such that there exists an edge from $x_1$ to $x_2$ in $G(\Gamma_1)$, that is $\alpha(x_1) \sqsubseteq \Gamma_1(x_2) = \Gamma(x_2)[\Gamma(x)/\alpha(x)]$. Then either $\alpha(x_1) \sqsubseteq \Gamma(x_2)$ or $\alpha(x) \sqsubseteq \Gamma(x_2)$ and $\alpha(x_1) \sqsubseteq \Gamma(x)$. Hence either there is an edge from $x_1$ to $x_2$ in $G(\Gamma)$ or there must exist edges from $x_1$ to $x$ and from $x$ to $x_2$ (and hence a path of length two from $x_1$ to $x_2$) in $G(\Gamma)$. Now the assertion of the Lemma is an immediate consequence of the above remark and Lemma 2.6. $\square$
<figure><img src="image_3.png" /><figcaption>Figure 4: Flow-sensitive typing rules for commands with output</figcaption></figure>

Let $\mathbf{def}(c)$ be the set of assigned variables in a program $c$, formally defined by:

$$ \mathbf{def}(c) \stackrel{\mathbf{def}}{=} \left\{ \begin{array}{ll} \{x\} & \text{if } c \equiv x := e \\ \emptyset & \text{if } c \equiv \mathbf{skip} \\ \mathbf{def}(c_1) \cup \mathbf{def}(c_2) & \text{if } c \equiv c_1; c_2 \\ \mathbf{def}(c_1) \cup \mathbf{def}(c_2) & \text{if } c \equiv \mathbf{If e then } c_1 \mathbf{else } c_2 \mathbf{fi} \\ \mathbf{def}(c) & \text{if } c \equiv \mathbf{While e Do c oD} \end{array} \right. $$

and let us denote $\mathbf{def}^I(c) \stackrel{\mathbf{def}}{=} \mathbf{def}(c) \cap (Var \setminus X_O)$ and $\mathbf{def}^O(c) \stackrel{\mathbf{def}}{=} \mathbf{def}(c) \cap X_O$.
We define the ordering over environments as usual:

$$ \Gamma_1 \sqsubseteq \Gamma_2 \stackrel{\mathbf{def}}{=} \bigwedge_{x \in Var} \Gamma_1(x) \sqsubseteq \Gamma_2(x). $$

We also define a restricted ordering over environments:

$$ \Gamma_1 \sqsubseteq_r \Gamma_2 \stackrel{\mathbf{def}}{=} \bigwedge_{x \in Var} \Gamma_1(x) \sqsubseteq \Gamma_2(x) \wedge \bigwedge_{o \in X_O, x \in Var} (\alpha(o) \sqsubseteq \Gamma_2(x) \Rightarrow \alpha(o) \sqsubseteq \Gamma_1(x)). $$

It is immediate that $\Gamma_1 \sqsubseteq_r \Gamma_2$ implies $\Gamma_1 \sqsubseteq \Gamma_2$. Intuitively, when enriching an environment using $\sqsubseteq_r$, we have the right to add only “real dependencies” (and not “symbolic” dependencies with respect to variables in $X_O$). We adapt this definition for elements $t_1, t_2 \in \mathcal{L}$ as well: we denote $t_1 \sqsubseteq_r t_2$ when $t_1 \sqsubseteq t_2$, and for all $o \in X_O$, $\alpha(o) \sqsubseteq t_2 \Rightarrow \alpha(o) \sqsubseteq t_1$, i.e. $t_2$ does not contain new symbolic dependencies w.r.t. $t_1$.

Next lemma is immediate from the definitions.

**Lemma 2.9.** Let $\Gamma_1, \Gamma_2, \Gamma_3$ such that $\Gamma_1 \sqsubseteq \Gamma_2$, $p_1, p_2 \in \mathcal{L}$, $o \in X_O$ and $X \subseteq X_O$ with $p_1 \sqsubseteq_r p_2$. Then $\Gamma_1 \sqsubsetneq_o \Gamma_2 \sqsubsetneq_o$, $\Gamma_1 \sqsubsetneq_o X \sqsubseteq \Gamma_2 \sqsubsetneq_o X$, $(p_1, \Gamma_1) \sqsubsetneq_o X \sqsubseteq (p_2, \Gamma_2) \sqsubsetneq_o X$ and $(p_1, \Gamma_1) \sqsubsetneq_o X \sqsubseteq (p_2, \Gamma_2) \sqsubsetneq_o X$. Moreover, $\Gamma_1 \sqsubsetneq_o X \sqsubseteq_r \Gamma_3$ implies that $\Gamma_3 \sqsubsetneq_o X = \Gamma_3$.

The last assertion of the lemma is a consequence of the remark that $\Gamma_1 \sqsubsetneq_o X \sqsubseteq_r \Gamma_3$ implies that $\Gamma_3$ does not contain more “symbolic dependencies” than $\Gamma_1 \sqsubsetneq_o X$, and $\Gamma_1 \sqsubsetneq_o X$
does not contain any “symbolic dependencies” with respect to variables in X. Obviously, using that $\sqsubseteq_r \subseteq \sqsubseteq$, all inequalities hold also when the premise $\Gamma_1 \sqsubseteq \Gamma_2$ is replaced by $\Gamma_1 \sqsubseteq_r \Gamma_2$.

**2.4. Typing rules.** For a command *c*, judgements have the form $p \vdash_{\alpha} \Gamma\{c\}\Gamma'$ where $p \in \mathcal{L}$ and $\Gamma$ and $\Gamma'$ are type environments well-formed. The inference rules are shown in Figure 4. The idea is that if $\Gamma$ describes the security levels of variables which hold before execution of *c*, then $\Gamma'$ will describe the security levels of those variables after execution of *c*. The type *p* represents the usual program counter level and serves to eliminate indirect information flows; the derivation rules ensure that all variables that can be changed by *c* will end up (in $\Gamma'$) with types greater than or equal to *p*. As usual, whenever $p = \perp$ we drop it and write $\vdash_{\alpha} \Gamma\{c\}\Gamma'$ instead of $\perp \vdash_{\alpha} \Gamma\{c\}\Gamma'$. Throughout this paper the type of an expression *e* is defined simply by taking the lub of the types of its free variables $\Gamma[\alpha](fv(e))$, for example the type of $x + y + o$ where *o* is the only output variable is $\Gamma(x) \sqcup \Gamma(y) \sqcup \alpha(o)$. This is consistent with the typing rules used in many systems, though more sophisticated typing rules for expressions would be possible in principle.

Let us explain some of the typing rules:

* The rule As1 is a standard rule for assignment, the new value of *x* depends on the variables occurring in the right-hand side *e*. Since *x* is not an output variable, we do not need to update the type of the other variables. Moreover, notice that considering the type of an expression to be $\Gamma[\alpha](fv(e))$ instead of $\Gamma(fv(e))$ allows to capture the dependencies with respect to the current values of output variables.

* The rule As2 captures the fact that when assigning an output variable *x* we need to update the types of all the other variables depending on the last previous value of *x*: $\Gamma_1 = \Gamma \prec_\alpha x$ express that *symbolic* dependencies with respect to the last previous value of *x* should be replaced with *real* dependencies with respect to the initial types of variables.

* The rule As3 is similar to As2 when the assigned variable *x* occurs also on the right-hand side.

* The rule Sub is the standard subtyping rule. Notice that we use relation $\sqsubseteq_r$ instead of $\sqsubseteq$ in order to prevent introducing circular dependencies.

* The rule If deals with conditional statements. In an If statement, the program counter level changes for the typing of each branch in order to take into account the indirect information flow. Moreover, at the end of the If command, we do the join of the two environments obtained after the both branches, but in order to prevent cycles, we first replace the “symbolic” dependencies by the corresponding “real” dependencies for each output variable that is assigned by the other branch.

In order to give some intuition about the rules, we present a simple example in Figure 5.

**Example 2.10.** Let $\{x, y, z, u\} \subseteq \text{Var} \setminus X_O$ and $\{o_1, o_2, o_3\} \subseteq X_O$ be some variables and let $\{X, Y, Z, U, O_1, O_2, O_3, \overline{O_1}, \overline{O_2}, \overline{O_3}\}$ be some atoms of a lattice of security levels. Let us assume that $\forall i \in \{1, 2, 3\}, \alpha(o_i) = \overline{O_i}$. We assume that the initial environment is $\Gamma_0 = [x \to X, y \to Y, z \to Z, u \to U, o_1 \to O_1, o_2 \to O_2, o_3 \to O_3]$. Since the types of variables *x*, *u* and *o*<sub>3</sub> do not change, we omit them in the following. We highlighted the changes with respect to the previous environment. After the first assignment, the type of *o*<sub>1</sub> becomes *X*, meaning that the current value of *o*<sub>1</sub> depends on the initial value of *x*. After the assignment *y* := *o*<sub>1</sub> + *z*, the type of *y* becomes $\overline{O_1} \sqcup Z$, meaning that the current value of *y* depends on the initial value of *z* and the current value of *o*<sub>1</sub>. After the assignment *o*<sub>1</sub> = *u*, the type of *y* becomes *X*sqcup *Z* as *o*<sub>1</sub> changed and we have to mirror this in the dependencies of *y*,
$$ (1) \quad o_1 := x + 1 \qquad \Gamma_0 = [y \to Y, z \to Z, o_1 \to O_1, o_2 \to O_2] $$

$$ (2) \quad y := o_1 + z \qquad \Gamma_1 = [y \to Y, z \to Z, \mathbf{o}_1 \to \mathbf{X}, o_2 \to O_2] $$

$$ (3) \quad o_1 := u \qquad \Gamma_2 = [y \to \overline{\mathbf{o}_1} \sqcup \mathbf{Z}, z \to Z, o_1 \to X, o_2 \to O_2] $$

$$ (4) \quad z := o_1 + o_3 \qquad \Gamma_3 = [y \to \mathbf{X} \sqcup \mathbf{Z}, z \to Z, \mathbf{o}_1 \to \mathbf{U}, o_2 \to O_2] $$

$$ (5) \quad \lfloor (o_2 = o_3 + x) \qquad \mathbf{p} = \overline{\mathbf{o}_3} \sqcup \mathbf{O}_2 \sqcup \mathbf{X} $$

$$ (6) \quad \text{then } o_1 := o_2 \qquad \Gamma_6 = [y \to X \sqcup Z, \mathbf{z} \to \mathbf{U} \sqcup \overline{\mathbf{o}_3}, \mathbf{o}_1 \to \overline{\mathbf{o}_3} \sqcup \mathbf{O}_2 \sqcup \mathbf{X} \sqcup \overline{\mathbf{o}_2}, o_2 \to O_2] $$

$$ (7) \quad \text{else } o_2 := o_1 \qquad \Gamma_7 = [y \to X \sqcup Z, z \to \overline{\mathbf{o}_1} \sqcup \overline{\mathbf{o}_3}, o_1 \to U, o_2 \to \overline{\mathbf{o}_3} \sqcup \mathbf{O}_2 \sqcup \mathbf{X} \sqcup \overline{\mathbf{o}_1}] $$

$$ (8) \quad \text{fi} \qquad \Gamma_8 = (\Gamma_6 \prec_{\alpha} o_2) \sqcup (\Gamma_7 \prec_{\alpha} o_1) = [y \to X \sqcup Z, \mathbf{z} \to \mathbf{U} \sqcup \overline{\mathbf{o}_3}, \\ o_1 \to \overline{\mathbf{o}_3} \sqcup \mathbf{O}_2 \sqcup \mathbf{X} \sqcup \mathbf{U}, o_2 \to \overline{\mathbf{o}_3} \sqcup \mathbf{O}_2 \sqcup \mathbf{X} \sqcup \mathbf{U}] $$

<caption>Figure 5: Example of application for our typing system</caption>

and the type of $o_1$ becomes $X$. When we enter in the `lf`, the program counter level changes to $p = \overline{O_3} \sqcup O_2 \sqcup X$ as the expression $o_2 = o_3 + x$ depends on the values of variables $o_2, o_3, x$, but $o_2$ and $o_3$ are output variables and $o_2$ will be assigned by the `lf` command, hence we replace the “symbolic” dependency $\alpha(o_2) = \overline{O_2}$ by its “real” dependency $\Gamma(o_2) = O_2$. At the end of the `lf` command, we do the join of the two environments obtained after the both branches, but in order to prevent cycles, we first replace the “symbolic” dependencies by the corresponding “real” dependencies for each output variable that is assigned by the other branch.

**2.5. Well-formed environments.** In this section we prove that, if the initial environment is well-formed, then all the environments generated by the typing system are well-formed too. To do so, the following lemma states some useful properties, where for any $p \in \mathcal{L}$, we denote by $\mathbf{atomO}(p) \stackrel{def}{=} \{o \in X_O \mid \alpha(o) \sqsubseteq p\}$.

**Lemma 2.11.** For all $\Gamma$, if $\mathcal{WF}(\Gamma)$ and $p \vdash_{\alpha} \Gamma\{c\}\Gamma'$ and $\mathbf{atomO}(p) \cap \mathbf{def}^O(c) = \emptyset$ then

(1) $\mathcal{WF}(\Gamma')$,

(2) for any $o \in X_O \setminus (\mathbf{def}^O(c) \sqcup \mathbf{atomO}(p))$, $\mathcal{GT}_{\Gamma'}(o) \subseteq \mathcal{GT}_{\Gamma}(o)$,

(3) for any $o \in \mathbf{atomO}(p)$, $\mathcal{GT}_{\Gamma'}(o) \subseteq \mathcal{GT}_{\Gamma}(o) \cup \mathbf{def}^O(c)$,

(4) for any $o \in \mathbf{def}^O(c)$, $\mathcal{GT}_{\Gamma'}(o) \subseteq \mathbf{def}^O(c)$,

(5) for any $x \notin \mathbf{def}(c)$, $(\Gamma \prec_{\alpha} \mathbf{def}^O(c))(x) \sqsubseteq_r \Gamma'(x)$.

*Proof.* Proof is by induction on the derivation of $p \vdash_{\alpha} \Gamma\{c\}\Gamma'$ for all assertions in the same time. We do a case analysis according to the last rule applied (case Skip is trivial).

(Ass1) $c$ is an assignment $x := e$ for some $x \notin X_O$.

Since $x \notin X_O$, it follows that $\mathcal{G}(\Gamma') = \mathcal{G}(\Gamma)$ and obviously for any $x \notin \mathbf{def}(c)$, $\Gamma(x) = \Gamma'(x)$ and $\sqsubseteq_{\Gamma} = \sqsubseteq_{\Gamma'}$ and $\mathcal{WF}(\Gamma)$ implies $\mathcal{WF}(\Gamma')$.
(Ass2) $c$ is an assignment $o := e$ for some $o \in X_O \setminus fv(e)$. Hence in this case $\mathbf{def}(c) = \mathbf{def}^O(c) = \{o\}$, and by assumption, $\alpha(o) \nsubseteq p$.

Then $\Gamma' = \Gamma_1[o \mapsto p \sqcup \Gamma_1[\alpha](fv(e))]$ with $\Gamma_1 = \Gamma \triangleleft_\alpha o$. By Lemma 2.8, $\mathcal{WF}(\Gamma_1)$, and using Lemma 2.6 we get that $\mathcal{WF}(\Gamma_1)$ does not contain any edge with origin $o$ and hence $\mathcal{WF}(\Gamma')$. The second part follows from the remark that using Lemma 2.8 we get $\sqsubseteq_{\Gamma_1} = \sqsubseteq_{\Gamma} \setminus \{(o, o') | o' \in X_O\}$ and $\sqsubseteq_{\Gamma'} = \sqsubseteq_{\Gamma_1} \cup \{(o', o) | o' \in \mathbf{atomO}(p)\}$, and for any $o' \neq o$, $\Gamma_1(o') = \Gamma(o')$. Hence, $\mathcal{GT}_{\Gamma'}(o) = \emptyset$. Finally, for any $x \notin \mathbf{def}(c)$, $(\Gamma \triangleleft_\alpha o)(x) = \Gamma_1(x) = \Gamma'(x)$.

(Ass3) $c$ is an assignment $o := e$ for some $o \in X_O \cap fv(e)$. Similar to the previous case.

(Seq) $c$ is $c_1; c_2$. Then $p \vdash_\alpha \Gamma\{c_1; c_2\}\Gamma_2$ was inferred based on $p \vdash_\alpha \Gamma\{c_1\}\Gamma_1$ and $p \vdash_\alpha \Gamma_1\{c_2\}\Gamma_2$. Let us denote $U_i = \mathbf{def}^O(c_i)$, for $i = 1, 2$.

Using the induction hypothesis for $p \vdash_\alpha \Gamma\{c_1\}\Gamma_1$ we get that $\mathcal{WF}(\Gamma_1)$, and for any $o \in X_O \setminus (U_1 \cup \mathbf{atomO}(p))$, $\mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_{\Gamma}(o)$, for any $o \in \mathbf{atomO}(p)$, $\mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_{\Gamma}(o) \cup U_1$ and for any $o \in U_1$, $\mathcal{GT}_{\Gamma_1}(o) \subseteq U_1$. In addition, for any $x \notin U_1$, $(\Gamma \triangleleft_\alpha U_1)(x) \sqsubseteq_r \Gamma_1(x)$.

Using the induction hypothesis for $p \vdash_\alpha \Gamma_1\{c_2\}\Gamma_2$ we get that $\mathcal{WF}(\Gamma_2)$, and for any $o \in X_O \setminus (U_2 \cup \mathbf{atomO}(p))$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o)$, for any $o \in \mathbf{atomO}(p)$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \cup U_2$ and for any $o \in U_2$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq U_2$. In addition, for any $x \notin U_2$, $(\Gamma_1 \triangleleft_\alpha U_2)(x) \sqsubseteq_r \Gamma_2(x)$.

Since $\mathbf{def}^O(c) = U_1 \cup U_2$, for any $o \in X_O \setminus (U_1 \cup U_2 \cup \mathbf{atomO}(p))$, we have both $o \in X_O \setminus (U_1 \cup \mathbf{atomO}(p))$ and $o \in X_O \setminus (U_2 \cup \mathbf{atomO}(p))$ and hence $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_{\Gamma}(o)$.

For any $o \in \mathbf{atomO}(p)$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \cup U_2 \subseteq \mathcal{GT}_{\Gamma}(o) \cup U_1 \cup U_2$.

Now, for any $o \in (U_1 \cup U_2)$, either $o \in U_2$ or $o \in U_1 \setminus U_2$. If $o \in U_2$, then $\mathcal{GT}_{\Gamma_2}(o) \subseteq U_2 \subseteq U_1 \cup U_2$. If $o \in U_1 \setminus U_2$, then $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \subseteq U_1 \subseteq U_1 \cup U_2$.

Finally, for any $x \notin \mathbf{def}(c)$, we have $(\Gamma \triangleleft_\alpha (U_1 \cup U_2)(x) = ((\Gamma \triangleleft_\alpha U_1) \triangleleft_\alpha U_2)(x) = ((\Gamma \triangleleft_\alpha U_1)(x), \Gamma \triangleleft_\alpha U_1) \triangleleft_\alpha U_2 \stackrel{(1)}{\sqsubseteq} ((\Gamma \triangleleft_\alpha U_1)(x), \Gamma_1) \triangleleft_\alpha U_2 \stackrel{(2)}{\sqsubseteq} (\Gamma_1(x), \Gamma_1) \triangleleft_\alpha U_2 = ((\Gamma_1 \triangleleft_\alpha U_2)(x) \sqsubseteq_r \Gamma_2(x)).$ We used whenever necessarily Lemma 2.11; in addition, in (1) we used that $(\Gamma \triangleleft_\alpha U_1)(x)$ does not depend on variables in $U_1$, and by induction hypothesis for all variables $v \notin U_1$, $(\Gamma \triangleleft_\alpha U_1)(v) \sqsubseteq_r \Gamma_1(v)$, in (2) we used that by induction hypothesis $(\Gamma \triangleleft_\alpha U_1)(x) \sqsubseteq_r \Gamma_1(x)$, in (3) we used that $x \notin U_2$, and hence by induction hypothesis, $(\Gamma_1 \triangleleft_\alpha U_2)(x) \sqsubseteq_r \Gamma_2(x)$.

(If) $c$ is if $e$ then $c_1$ else $c_2$ fi. Then $p \vdash_\alpha \Gamma\{\text{If } e \text{ then } c_1 \text{ else } c_2 \text{ fi } \} \Gamma'$ was inferred based on $p \sqcup p' \vdash_\alpha \Gamma\{c_i\}\Gamma_i$, where $p' = (\Gamma[\alpha](fv(e)), \Gamma) \triangleleft_\alpha (\mathbf{def}^O(c_1) \cup \mathbf{def}^O(c_2))$ and $\Gamma' = \Gamma'_1 \sqcup \Gamma'_2$ where $\Gamma'_1 = \Gamma_1 \triangleleft_\alpha \mathbf{def}^O(c_2)$ and $\Gamma'_2 = \Gamma_2 \triangleleft_\alpha \mathbf{def}^O(c_1)$. Let us denote $U_i = \mathbf{def}^O(c_i)$, for $i = 1, 2$. First notice that $\mathbf{atomO}(p) \cap (U_1 \cup U_2) = \emptyset$ ensures that $\mathbf{atomO}(p \sqcup p') \cap (U_1 \cup U_2) = \emptyset$.

Using the induction hypothesis for $p \sqcup p' \vdash_\alpha \Gamma\{c_1\}\Gamma_1$ we get that $\mathcal{WF}(\Gamma_1)$, and for any $o \in X_O \setminus (U_1 \cup \mathbf{atomO}(p \sqcup p'))$, $\mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_{\Gamma}(o)$, for any $o \in \mathbf{atomO}(p \sqcup p')$, $\mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_{\Gamma}(o) \cup U_1$ and for any $o \in U_1$, $\mathcal{GT}_{\Gamma_1}(o) \subseteq U_1$. In addition, for any $x \notin U_1$, $(\Gamma \triangleleft_\alpha U_1)(x) \sqsubseteq_r \Gamma_1(x)$.

Using the induction hypothesis for $p \sqcup p' \vdash_\alpha \Gamma\{c_2\}\Gamma_2$ we get that $\mathcal{WF}(\Gamma_2)$, and for any $o \in X_O \setminus (U_2 \cup \mathbf{atomO}(p \sqcup p'))$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma}(o)$, for any $o \in \mathbf{atomO}(p \sqcup p')$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_{\Gamma}(o) \cup U_2$ and for any $o \in U_2$, $\mathcal{GT}_{\Gamma_2}(o) \subseteq U_2$. In addition, for any $x \notin U_2$, $(\Gamma \triangleleft_\alpha U_2)(x) \sqsubseteq_r \Gamma_2(x)$.
For any $o \in X_O \setminus (U_1 \cup U_2 \cup \mathbf{atomO}(p \sqcup p'))$, $\mathcal{GT}_{\Gamma'_1 \cup \Gamma'_2}(o) = \mathcal{GT}_{(\Gamma_1 \prec_\alpha U_2) \cup (\Gamma_2 \prec_\alpha U_1)}(o) \subseteq \mathcal{GT}_\Gamma(o)$ since both $\mathcal{GT}_{\Gamma_1 \prec_\alpha U_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_\Gamma(o)$ and $\mathcal{GT}_{\Gamma_2 \prec_\alpha U_1}(o) \subseteq \mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_\Gamma(o)$.

For any $o \in U_1$, $\mathcal{GT}_{\Gamma_2 \prec_\alpha U_1}(o) = \emptyset$ and by induction hypothesis $\mathcal{GT}_{\Gamma_1 \prec_\alpha U_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \subseteq U_1$. For any $o \in U_2$, $\mathcal{GT}_{\Gamma_1 \prec_\alpha U_2}(o) = \emptyset$ and by induction hypothesis $\mathcal{GT}_{\Gamma_2 \prec_\alpha U_1}(o) \subseteq \mathcal{GT}_{\Gamma_2}(o) \subseteq U_2$. This implies that for any $o \in (U_1 \cup U_2)$, $\mathcal{GT}_{\Gamma'_1 \cup \Gamma'_2}(o) = \mathcal{GT}_{(\Gamma_1 \prec_\alpha U_1) \cup (\Gamma_2 \prec_\alpha U_2)}(o) \subseteq U_1 \cup U_2$.

For any $o \in \mathbf{atomO}(p \sqcup p')$, by induction hypothesis $\mathcal{GT}_{\Gamma_1 \prec_\alpha U_2}(o) \subseteq \mathcal{GT}_{\Gamma_1}(o) \subseteq \mathcal{GT}_\Gamma(o) \cup U_1$ and $\mathcal{GT}_{\Gamma_2 \prec_\alpha U_1}(o) \subseteq \mathcal{GT}_{\Gamma_2}(o) \subseteq \mathcal{GT}_\Gamma(o) \cup U_2$. We already proved that for any $o \in (U_1 \cup U_2)$, $\mathcal{GT}_{\Gamma'_1 \cup \Gamma'_2}(o) \subseteq U_1 \cup U_2$. The previous inclusions imply that for any $o \in \mathbf{atomO}(p \sqcup p')$, $\mathcal{GT}_{\Gamma'_1 \cup \Gamma'_2}(o) \subseteq \mathcal{GT}_\Gamma(o) \cup U_1 \cup U_2$.

Now if we assume by contradiction that $\neg W\mathcal{F}(\Gamma')$, we get that there must exist $x_1, x_2 \in X_O$ such that $x_1 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_2$ and $x_2 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_1$. We make an analysis by case:

- $x_1 \in U_1 \cap U_2$. Impossible, since we have that $W\mathcal{F}(\Gamma_1 \prec_\alpha U_2)$ and $W\mathcal{F}(\Gamma_2 \prec_\alpha U_1)$, and for any $o \in X_O$, $x_1 \not\sqsubseteq_{\Gamma_1 \prec_\alpha U_2} o$ and $x_1 \not\sqsubseteq_{\Gamma_2 \prec_\alpha U_1} o$.

- $x_1, x_2 \in U_1 \setminus U_2$. From induction hypothesis we get $\mathcal{GT}_{\Gamma'_1}(x_i) \subseteq U_1$ and $\mathcal{GT}_{\Gamma'_2}(x_i) = \emptyset$. This implies that for any $x \in \mathcal{GT}_{\Gamma'_1}(x_i)$, it holds $x \in U_1$ and hence $\mathcal{GT}_{\Gamma'_2}(x) = \emptyset$. It means that $x_1 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_2$ and $x_2 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_1$ implies that $x_1 \sqsubseteq_{\Gamma'_1} x_2$ and $x_2 \sqsubseteq_{\Gamma'_1} x_1$ which contradicts $W\mathcal{F}(\Gamma'_1)$.

- $x_1 \in U_1 \setminus U_2$ and $x_2 \notin U_1$. From induction hypothesis we get $\mathcal{GT}_{\Gamma'_1}(x_1) \subseteq U_1$ and $\mathcal{GT}_{\Gamma'_2}(x_1) = \emptyset$. This implies that for any $x \in \mathcal{GT}_{\Gamma'_1}(x_1)$, it holds $x \in U_1$ and hence $\mathcal{GT}_{\Gamma'_2}(x) = \emptyset$. It means that $x_1 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x$ implies that $x \in \mathcal{GT}_{\Gamma'_1}(x_1) \subseteq U_1$, contradiction with $x_2 \notin U_1$ and $x_1 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_2$.

- $x_1 \notin U_1 \cup U_2$ and $x_2 \notin U_1 \cup U_2$. In this case, by induction $\mathcal{GT}_{\Gamma'_1 \cup \Gamma'_2}(x_1) \subseteq \mathcal{GT}_\Gamma(x_1) \cup (U_1 \cup U_2)$ and $\mathcal{GT}_{\Gamma'_1 \cup \Gamma'_2}(x_2) \subseteq \mathcal{GT}_\Gamma(x_2) \cup (U_1 \cup U_2)$. Hence $x_1 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_2$ implies that $x_1 \sqsubseteq_\Gamma x_2$, $x_2 \sqsubseteq_{\Gamma'_1 \cup \Gamma'_2} x_1$ implies that $x_2 \sqsubseteq_\Gamma x_1$, contradiction with $W\mathcal{F}(\Gamma)$.

- The remaining cases are symmetrical ones with the previous cases.

(While) Similar to the rule (If).

(Sub) Trivial from the premises of the rule, using the induction hypothesis, the transitivity of $\sqsubseteq_r$ and that $\Gamma_1 \sqsubseteq_r \Gamma_2$ implies that $\mathcal{G}(\Gamma_1) = \mathcal{G}(\Gamma_2)$. $\square$

**2.6. Soundness of the typing system.** As already stated above, our type system aims to capture the following non-interference condition: given a derivation $p \vdash_\alpha \Gamma\{c\}\Gamma'$, the final value of a variable $x$ with final type $t \sqcup \alpha(X_O)$, should depend at most on the initial values of those variables $y$ with initial types $\Gamma(y) \sqsubseteq t$ and on the final values of variables in $X_O$. Or otherwise said, executing a program $c$ on two initial states $\sigma$ and $\rho$ such that $\sigma(y) = \rho(y)$ for all $y$ with $\Gamma(y) \sqsubseteq t$ which ends with two final states $\sigma'$ and $\rho'$ such that $\sigma'(o) = \rho'(o)$ for all $o \in X_O$ will satisfy $\sigma'(x) = \rho'(x)$ for all $x$ with $\Gamma'(x) \sqsubseteq t \sqcup \alpha(X_O)$. In order to prove the soundness of the typing system, we need a stronger invariant denoted $\mathcal{I}(t, \Gamma)$: intuitively, $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$ means that for each variable $x$ and $A \subseteq X_O$, if $\sigma =_A \rho$ and $\Gamma(x) \sqsubseteq t \sqcup \alpha(A)$, then $\sigma(x) = \rho(x)$. Formally, given $t \in \mathcal{L}$ and $\Gamma: \mathrm{Var} \mapsto \mathcal{L}$, we define
$$ \mathcal{I}(t, \Gamma) \stackrel{\mathrm{def}}{=} \bigcap_{A \subseteq X_O} \Gamma_{A, \alpha(A) \sqcup t} $$

The following lemmas provide some useful properties satisfied by the invariant $\mathcal{I}(t, \Gamma)$.
**Lemma 2.12.** If $\Gamma_1 \sqsubseteq \Gamma_2$ then for all $t \in \mathcal{L}$, $\mathcal{I}(t, \Gamma_1) \subseteq \mathcal{I}(t, \Gamma_2)$.

*Proof.* Assume $(\sigma, \rho) \in \mathcal{I}(t, \Gamma_1)$. We prove that $(\sigma, \rho) \in \mathcal{I}(t, \Gamma_2)$. Let $A \subseteq X_O$ and let $y \in \text{Var}$ such that $\Gamma_2(y) \sqsubseteq \alpha(A) \sqcup t$. Assume that $\sigma =_A \rho$. We have to prove that $\sigma(y) = \rho(y)$. We have $\Gamma_1(y) \sqsubseteq \Gamma_2(y) \sqsubseteq \alpha(A) \sqcup t$, and since $(\sigma, \rho) \in \mathcal{I}(t, \Gamma_1)$ and $\sigma =_A \rho$, we get $\sigma(y) = \rho(y)$. $\square$

**Lemma 2.13.** Let $x \in X_O$, $X \subseteq X_O$ and let $\Gamma$ be well-formed. Let $\Gamma_1 = \Gamma \prec_{\alpha} x$ and $\Gamma_2 = \Gamma \prec_{\alpha} X$. Then for all $t \in \mathcal{L}$, it holds $\mathcal{I}(t, \Gamma) \subseteq \mathcal{I}(t, \Gamma_1)$ and $\mathcal{I}(t, \Gamma) \subseteq \mathcal{I}(t, \Gamma_2)$.

*Proof.* We prove only the first inclusion, the second one can be easily proved by induction using the first one.

Let $\sigma, \rho$ such that $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$ and let us prove that $(\sigma, \rho) \in \mathcal{I}(t, \Gamma_1)$.

Let $B \subseteq X_O$ and let $y \in \text{Var}$ such that $\Gamma_1(y) \sqsubseteq \alpha(B) \sqcup t$. Assume that $\sigma =_B \rho$. We have to prove that $\sigma(y) = \rho(y)$.

Then $\Gamma_1(y) \sqsubseteq \alpha(B) \sqcup t$ implies that $(\Gamma(y))[\Gamma(x)/\alpha(x)] \sqsubseteq \alpha(B) \sqcup t$. That is, either $\Gamma(y) \sqsubseteq \alpha(B) \sqcup t$ or $\Gamma(y) \sqsubseteq \alpha(B) \sqcup \alpha(x) \sqcup t$ and $\Gamma(x) \sqsubseteq \alpha(B) \sqcup t$.

* If $\Gamma(y) \sqsubseteq \alpha(B) \sqcup t$, since $\sigma =_B \rho$ and $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$ we get $\sigma(y) = \rho(y)$.

* If $\Gamma(y) \sqsubseteq \alpha(B) \sqcup \alpha(x) \sqcup t$ and $\Gamma(x) \sqsubseteq \alpha(B) \sqcup t$, from $\sigma =_B \rho$ and $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$, we get $\sigma =_{\{x\}} \rho$, and hence $\sigma =_{B \cup \{x\}} \rho$. Since $\Gamma(y) \sqsubseteq \alpha(B) \sqcup \alpha(x) \sqcup t$ and $\sigma =_{\Gamma, B \cup \{x\}, \alpha(B \cup \{x\}) \sqcup t} \rho$, we get $\sigma(y) = \rho(y)$. $\square$

**Lemma 2.14.** Let $o \in X_O$ and let $\Gamma' = \Gamma \prec_{\alpha} o$ with well formed $\mathcal{WF}(\Gamma)$. Let $t \in \mathcal{L}$ and let $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$. For any $A \subseteq X_O$ such that $\sigma =_{A \setminus \{o\}} \rho$ and for any $y \in \text{Var}$ such that $\Gamma'(y) \sqsubseteq \alpha(A) \sqcup t$ it holds that $\sigma(y) = \rho(y)$.

*Proof.* $\mathcal{WF}(\Gamma)$ and $\Gamma'(y) \sqsubseteq \alpha(A) \sqcup t$ implies that $(\Gamma(y))[\Gamma(o)/\alpha(o)] \sqsubseteq \alpha(A \setminus \{o\}) \sqcup t$. That is, either $\Gamma(y) \sqsubseteq \alpha(A \setminus \{o\}) \sqcup t$ or $\Gamma(y) \sqsubseteq \alpha(A) \sqcup t$ and $\Gamma(o) \sqsubseteq \alpha(A \setminus \{o\}) \sqcup t$.

* If $\Gamma(y) \sqsubseteq \alpha(A \setminus \{o\}) \sqcup t$, as $\sigma =_{A \setminus \{o\}} \rho$ and $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$ we get $\sigma(y) = \rho(y)$.

* If $\Gamma(y) \sqsubseteq \alpha(A) \sqcup t$ and $\Gamma(o) \sqsubseteq \alpha(A \setminus \{o\}) \sqcup t$, from $\sigma =_{A \setminus \{o\}} \rho$ and $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$, we get $\sigma =_{\{o\}} \rho$, and hence $\sigma =_A \rho$. Since $\Gamma(y) \sqsubseteq \alpha(A) \sqcup t$ and $\sigma =_{\Gamma, A, \alpha(A) \sqcup t} \rho$, we get $\sigma(y) = \rho(y)$. $\square$

**Lemma 2.15.** Let $\Gamma' = \Gamma \prec_{\alpha} U$ for a well formed $\mathcal{WF}(\Gamma)$ where $U = \{o_1, \dots, o_n\} \subseteq X_O$. Let $t \in \mathcal{L}$ and let $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$. For any $A \subseteq X_O$ such that $\sigma =_{A \setminus U} \rho$ and for any $y \in \text{Var}$ such that $\Gamma'(y) \sqsubseteq \alpha(A) \sqcup t$ it holds that $\sigma(y) = \rho(y)$.

*Proof.* By induction on $n$. The case $n = 1$ follows from the lemma 2.14. Let us denote $U_{n-1} = U \setminus \{o_n\} = \{o_1, \dots, o_{n-1}\}$. and let $\Gamma_{n-1} = \Gamma \prec_{\alpha} U_{n-1}$. Hence $\Gamma' = \Gamma_{n-1} \prec_{\alpha} o_n$.

By lemma 2.8, $\Gamma_{n-1}$ is well formed too. $\mathcal{WF}(\Gamma_{n-1})$ and $\Gamma'(y) \sqsubseteq \alpha(A) \sqcup t$ implies that $(\Gamma_{n-1}(y))[\Gamma_{n-1}(o_n)/\alpha(o_n)] \sqsubseteq \alpha(A \setminus \{o_n\}) \sqcup t$. That is, either $\Gamma_{n-1}(y) \sqsubseteq \alpha(A \setminus \{o_n\}) \sqcup t$ or $\Gamma_{n-1}(y) \sqsubseteq \alpha(A) \sqcup t$ and $\Gamma_{n-1}(o_n) \sqsubseteq \alpha(A \setminus \{o_n\}) \sqcup t$.

* If $\Gamma_{n-1}(y) \sqsubseteq \alpha(A \setminus \{o_n\}) \sqcup t$, since $\sigma =_{(A \setminus \{o_n\}) \setminus U_{n-1}} \rho$, by induction (taking $U' = \{o_1, \dots, o_{n-1}\}$ and $A' = A \setminus \{o_n\}$) we get $\sigma(y) = \rho(y)$.

* If $\Gamma_{n-1}(y) \sqsubseteq \alpha(A) \sqcup t$ and $\Gamma_{n-1}(o_n) \sqsubseteq \alpha(A \setminus \{o_n\}) \sqcup t$, since $\sigma =_{(A \setminus \{o_n\}) \setminus U_{n-1}} \rho$, we get by induction (taking $U' = U_{n-1}$ and $A' = A \setminus \{o_n\}$) that $\sigma =_{\{o_n\}} \rho$, and hence $\sigma =_{A \setminus U_{n-1}} \rho$. From $\Gamma_{n-1}(y) \sqsubseteq \alpha(A) \sqcup t$ and $\sigma =_{A \setminus U_{n-1}} \rho$ using the induction again (taking $U' = U_{n-1}$ and $A' = A$) we get $\sigma(y) = \rho(y)$. $\square$

The following theorem states the soundness of our typing system.
**Theorem 2.16.** Let us assume that $\mathcal{WF}(\Gamma)$ and $\forall o \in X_O, \alpha(o) \nsubseteq t$. If $p \vdash_{\alpha} \Gamma\{c\}\Gamma'$ then $c : \mathcal{I}(t, \Gamma) \Rightarrow \mathcal{I}(t, \Gamma')$.

*Proof.* Proof is by induction on the derivation of $p \vdash_{\alpha} \Gamma\{c\}\Gamma'$. Let $\sigma, \sigma', \rho, \rho'$ such that $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$ and $\langle c, \sigma \rangle \Rightarrow \sigma'$ and $\langle c, \rho \rangle \Rightarrow \rho'$. We prove that $(\sigma', \rho') \in \mathcal{I}(t, \Gamma')$.

Let $A \subseteq X_O$ and let $y \in \text{Var}$ such that $\Gamma'(y) \subseteq \alpha(A) \sqcup t$. Assume that $\sigma' =_A \rho'$. We have to prove that $\sigma'(y) = \rho'(y)$.

We do a case analysis according to the last rule applied (case Skip is trivial).

(Ass1) $c$ is an assignment $x := e$ for some $x \notin X_O$.

Then $\Gamma' = \Gamma[x \mapsto p \sqcup \Gamma[\alpha](fv(e))]$. Hence $\sigma' =_A \rho'$ implies $\sigma =_A \rho$.

If $y \not\equiv x$, then $\Gamma(y) = \Gamma'(y) \subseteq \alpha(A) \sqcup t$, and since $\sigma =_{\Gamma,A,\alpha(A)\sqcup t} \rho$, we get $\sigma'(y) = \sigma(y) = \rho(y) = \rho'(y)$. Let us assume that $c$ is $y := e$ for some $e$ and $y \notin X_O$. Then $\Gamma[\alpha](fv(e)) \subseteq \Gamma'(y) \subseteq \alpha(A) \sqcup t$, and this implies that: 1) for all variables $v \in fv(e) \setminus X_O$, $\Gamma(v) \subseteq \alpha(A) \sqcup t$, hence $\sigma(v) = \rho(v)$ and 2) for all variables $v \in fv(e) \cap X_O$, $\alpha(v) \subseteq \alpha(A) \sqcup t$, hence $v \in A$ and $\sigma(v) = \rho(v)$. We get that $\sigma(e) = \rho(e)$, and hence $\sigma'(y) = \rho'(y)$.

(Ass2) $c$ is an assignment $o := e$ for some $o \in X_O \setminus fv(e)$.

Using Lemma 2.13, we get that $(\sigma, \rho) \in \mathcal{I}(t, \Gamma_1)$, where $\Gamma_1 = \Gamma \prec_{\alpha} o$ and $\Gamma' = \Gamma_1[o \mapsto p \sqcup \Gamma_1[\alpha](fv(e) \setminus o)]$.

If $y \not\equiv o$, then $\Gamma_1(y) = \Gamma'(y) \subseteq \alpha(A) \sqcup t$, and since $\sigma =_{\Gamma_1,A,\alpha(A)\sqcup t} \rho$, we get $\sigma'(y) = \sigma(y) = \rho(y) = \rho'(y)$.

If $y \equiv o$, then $p \sqcup \Gamma_1[\alpha](fv(e) \setminus o) = \Gamma'(o) \subseteq \alpha(A) \sqcup t$, and this implies that: 1) for all variables $v \in fv(e) \setminus X_O$, $\Gamma_1(v) \subseteq \alpha(A) \sqcup t$, hence $\sigma(v) = \rho(v)$ and 2) for all variables $v \in fv(e) \cap X_O$, $\alpha(v) \subseteq \alpha(A) \sqcup t$, hence $v \in A$ and $\sigma(v) = \rho(v)$. We get that $\sigma(e) = \rho(e)$, and hence $\sigma'(y) = \rho'(y)$.

(Ass3) $c$ is an assignment $o := e$ for some $o \in X_O \cap fv(e)$. Similar to the previous case, using the remark that $\Gamma(o) \subseteq \alpha(A) \sqcup t$ implies that $\sigma(o) = \rho(o)$.

(Seq) Trivial, using the transitivity of $\Rightarrow$.

(If) Let us denote $U_i = \{o_1^i, o_2^i, \dots, o_n^i\} = \mathbf{def}^O(c_i)$ for $i = 1, 2$ for some good orderings $U_i$ of $\mathbf{def}^O(c_i)$.

- If $(\Gamma[\alpha](fv(e)), \Gamma) \prec_{\alpha} (U_1 \cup U_2) \nsubseteq \Gamma'(y)$, obviously we get $y \notin \mathbf{def}(c)$, i.e. $c$ contains no assignments to $y$. Hence $\sigma'(y) = \sigma(y)$ and $\rho(y) = \rho'(y)$. Then from Lemma 2.13, we get that $(\Gamma \prec_{\alpha} (U_1 \cup U_2))(y) \subseteq_r \Gamma'(y) \subseteq \alpha(A) \sqcup t$. Moreover, $\sigma' =_A \rho'$ implies that $\sigma =_{A\setminus(U_1 \cup U_2)} \rho$ and using Lemma 2.15 we get $\sigma(y) = \rho(y)$, and hence $\sigma'(y) = \sigma(y) = \rho(y) = \rho'(y)$.

- Let us suppose that $(\Gamma[\alpha](fv(e)), \Gamma) \prec_{\alpha} (U_1 \cup U_2) \subseteq \Gamma'(y)$. We denote $\Gamma_0^i = \Gamma \prec_{\alpha} U_i$. Then $(\Gamma[\alpha](fv(e)), \Gamma) \prec_{\alpha} (U_1 \cup U_2) \subseteq \Gamma'(y) \subseteq \alpha(A) \sqcup t$, and this implies that $(\Gamma[\alpha](fv(e)), \Gamma) \prec_{\alpha} (U_1 \cup U_2) \subseteq \alpha(A \setminus (U_1 \cup U_2)) \sqcup t$. Moreover, $\sigma' =_A \rho'$ implies that $\sigma =_{A\setminus(U_1 \cup U_2)} \rho$. Using Lemma 2.15, we get for each variable $v \in fv(e)$ that $\sigma(v) = \rho(v)$. This proves that $\sigma(e) = \rho(e)$ and hence both executions $\langle c, \sigma \rangle \Rightarrow \sigma'$ and $\langle c, \rho \rangle \Rightarrow \rho'$ take the same branch $i$. Then we use the induction hypothesis applied to $p \sqcup p' \vdash_{\alpha} \Gamma\{c_i\}\Gamma_i$ to get that $(\sigma', \rho') \in \mathcal{I}(t, \Gamma_i)$, and then, since $\Gamma' = \Gamma_1 \prec_{\alpha} U_2 \sqcup \Gamma_2 \prec_{\alpha} U_1$, we use Lemmas 2.12 and 2.13 to conclude $(\sigma', \rho') \in \mathcal{I}(t, \Gamma')$.

(While) $c$ is While $e$ Do $c_1$ oD. Then $p \vdash_{\alpha} \Gamma\{c\}\Gamma'$ was inferred based on $p \sqcup p_e \vdash_{\alpha} \Gamma'\{c\}\Gamma_1$ and $(\Gamma \prec_{\alpha} U) \sqcup (\Gamma_1 \prec_{\alpha} U) \subseteq_r \Gamma'$ where $U = \mathbf{def}^O(c)$ and $p_e = \Gamma'[\alpha](fv(e))$. From $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$, using Lemma 2.13, we get $(\sigma, \rho) \in \mathcal{I}(t, \Gamma \prec_{\alpha} U)$ and using now Lemma 2.12 and the inequality $\Gamma \prec_{\alpha} U \subseteq (\Gamma \prec_{\alpha} U) \sqcup (\Gamma_1 \prec_{\alpha} U) \subseteq_r \Gamma'$, we obtain
<figure><img src="image_4.png" /><figcaption>Figure 6: Syntax and Labeled Operational semantics</figcaption></figure>

($\sigma, \rho) \in \mathcal{I}(t, \Gamma')$. Using the induction hypothesis applied to $p \sqcup p_e \vdash_{\alpha} \Gamma'\{c\}\Gamma_1$, we get that $(\sigma', \rho') \in \mathcal{I}(t, \Gamma_1)$. We apply again Lemma 2.13 and we get $(\sigma', \rho') \in \mathcal{I}(t, \Gamma_1 \triangleleft_{\alpha} U)$, and using Lemma 2.12 and that $(\Gamma \triangleleft_{\alpha} U) \sqcup (\Gamma_1 \triangleleft_{\alpha} U) \sqsubseteq_r \Gamma'$, we obtain $(\sigma', \rho') \in \mathcal{I}(t, \Gamma')$. (Sub) Trivial, from Lemma 2.12 and the induction hypothesis. $\square$

**2.7. Soundness w.r.t. to output-sensitive non-interference.** In this section we show how we can use the typing system in order to prove that a program *c* is output-sensitive noninterferent. Let $Var^e = Var \cup \{\bar{o} | o \in X_O\}$. Let us define $\mathcal{L} \stackrel{\text{def}}{=} \{\tau_A \mid A \subseteq Var^e\}$. We denote $\perp = \tau_\emptyset$ and $\top = \tau_{Var^e}$ and we consider the lattice $(\mathcal{L}, \perp, \top, \sqsubseteq)$ with $\tau_A \sqcup \tau_{A'} \stackrel{\text{def}}{=} \tau_{A \cup A'}$ and $\tau_A \sqsubseteq \tau_{A'}$ iff $A \sqsubseteq A'$. Obviously, $\mathcal{L}$ is a bounded atomistic lattice, its set of atoms being $\{\tau_x \mid x \in Var\} \cup \{\tau_{\bar{o}} \mid o \in X_O\}$.

The following Theorem is a consequence of the Definition 2.1 and Theorem 2.16.

**Theorem 2.17.** Let $\mathcal{L}$ be the lattice described above. Let $(\Gamma, \alpha)$ be defined by $\Gamma(x) = \{\tau_x\}$, for all $x \in Var$ and $\alpha(o) = \{\tau_{\bar{o}}\}$, for all $o \in X_O$. If $\vdash_{\alpha} \Gamma\{c\}\Gamma'$ and for all $x_l \in X_L$, $\Gamma'(x_l) \sqsubseteq \Gamma(X_I) \sqcup \alpha(X_O)$, then *c* is $(X_I, X_O, X_L)$-secure.

*Proof.* Let $t = \Gamma(X_I)$. First, we prove that if $\sigma =_{X_I} \rho$, then $(\sigma, \rho) \in \mathcal{I}(t, \Gamma)$. Let $A \subseteq X_O$ such that $\sigma =_A \rho$ and let $y \in Var$ such that $\Gamma(y) \sqsubseteq \alpha(A) \sqcup t = \alpha(A) \sqcup \Gamma(X_I)$. This implies that $y \in X_I$, and since $\sigma =_{X_I} \rho$, we get $\sigma(y) = \rho(y)$.

Now let $\sigma, \sigma', \rho, \rho'$, such $\langle c, \sigma \rangle \implies \sigma'$ and $\langle c, \rho \rangle \implies \rho'$ and $\sigma =_{X_I} \rho$ and $\sigma' =_{X_O} \rho'$. Let $x_l \in X_L$. We have to prove that $\sigma' =_{X_l} \rho'$. Let us apply the Theorem 2.16 with $t = \Gamma(X_I)$. Since $\vdash_{\alpha} \Gamma\{c\}\Gamma'$ and $(\sigma, \rho) \in \mathcal{I}_1(t, \Gamma)$, we get that $(\sigma', \rho') \in \mathcal{I}(t, \Gamma')$. It means that $\sigma' =_{\Gamma', X_O, \alpha(X_O) \sqcup \Gamma(X_I)} \rho'$. Since by hypothesis we have that $\sigma' =_{X_O} \rho'$ and $\Gamma'(x_l) \sqsubseteq \alpha(X_O) \sqcup \Gamma(X_I)$, we get that $\sigma' =_{x_l} \rho'$. $\square$

### 3. OUTPUT-SENSITIVE CONSTANT-TIME

In this section we illustrate how our approach can be applied to a more realistic setting, considering a specific side-channel leakage due to the cache usage. However, this approach could be applied to any other side-channel setting as soon as one can model the leakage produced by each command.

Following [1, 4], we consider two types of cache-based information leaks: (i) disclosures that happen when secret data determine which parts of the program are executed; (ii)
$$ \text{As1'} \quad \frac{x \notin X_O}{p \vdash_{\alpha}^{ct} \Gamma \{x := e\} \Gamma[x \mapsto p \sqcup \Gamma[\alpha](fv(e))][x_l \mapsto \Gamma(x_l) \sqcup \Gamma[\alpha](fv(\vec{f}))]} $$

$$ x \notin X_O $$

$$ \text{Ast'} \quad \frac{p_1 = (\Gamma[\alpha](fv(e_1), fv(e)) \qquad p_l = (\Gamma[\alpha](fv(e_1), fv(\vec{f})))}{p \vdash_{\alpha}^{ct} \Gamma \{x[e_1] := e\} \Gamma[x \mapsto p \sqcup \Gamma(x) \sqcup p_1][x_l \mapsto \Gamma(x_l) \sqcup p_l]} $$

$$ \text{As2'} \quad \frac{x \in X_O \setminus fv(e)}{p \vdash_{\alpha}^{ct} \Gamma \{x := e\} \Gamma_1[x \mapsto p \sqcup \Gamma_1[\alpha](fv(e))][x_l \mapsto \Gamma_1(x_l) \sqcup \Gamma_1[\alpha](fv(\vec{f})))]} \quad \Gamma_1 = \Gamma \triangleleft_{\alpha} x $$

$$ \text{As3'} \quad \frac{x \in X_O \cap fv(e)}{p \vdash_{\alpha}^{ct} \Gamma \{x := e\} \Gamma_1[x \mapsto p \sqcup \Gamma(x) \sqcup \Gamma_1[\alpha](fv(e) \setminus x)][x_l \mapsto \Gamma_1(x_l) \sqcup \Gamma_1[\alpha](fv(\vec{f})))]} \quad \Gamma_1 = \Gamma \triangleleft_{\alpha} x $$

$$ \text{Skip} \quad \frac{p \vdash_{\alpha}^{ct} \Gamma \{skip\}}{p \vdash_{\alpha}^{ct} \Gamma \{skip\}} $$

$$ \text{Seq} \quad \frac{p \vdash_{\alpha}^{ct} \Gamma \{c_1\} \Gamma_1 \qquad p \vdash_{\alpha}^{ct} \Gamma_1 \{c_2\} \Gamma_2}{p \vdash_{\alpha}^{ct} \Gamma \{c_1; c_2\} \Gamma_2} $$

$$ \text{Sub} \quad \frac{p_0 \sqsubseteq_r p_1 \quad \Gamma \sqsubseteq_r \Gamma' \quad p_1 \vdash_{\alpha}^{ct} \Gamma' \{c\} \Gamma'_1 \quad \Gamma'_1 \sqsubseteq_r \Gamma_1}{p_0 \vdash_{\alpha}^{ct} \Gamma \{c\} \Gamma_1} $$

$$ p_l = \Gamma[\alpha](fv(e)) $$

$$ p \sqcup p' \vdash_{\alpha}^{ct} \Gamma[x_l \mapsto \Gamma(x_l) \sqcup p_l] \{c_i\} \Gamma_i $$

$$ \text{If} \quad \frac{p' = (p_l, \Gamma) \triangleleft_{\alpha} (\mathbf{def}^{\mathbf{O}}(c_1) \sqcup \mathbf{def}^{\mathbf{O}}(c_2)) \quad \Gamma' = \Gamma_1 \triangleleft_{\alpha} \mathbf{def}^{\mathbf{O}}(c_2) \sqcup \Gamma_2 \triangleleft_{\alpha} \mathbf{def}^{\mathbf{O}}(c_1)}{p \vdash_{\alpha}^{ct} \Gamma \{\text{If e then } c_1 \text{ else } c_2 \text{ fi } \} \Gamma'} $$

$$ p_l = \Gamma[\alpha](fv(e)) $$

$$ p \sqcup p_e \vdash_{\alpha}^{ct} \Gamma_1[x_l \mapsto \Gamma(x_l) \sqcup p_e] \{c\} \Gamma' $$

$$ \text{Wh} \quad \frac{p_e = \Gamma_1[\alpha](fv(e)) \quad \Gamma[x_l \mapsto \Gamma(x_l) \sqcup p_l] \sqcup ((\Gamma'[x_l \mapsto \Gamma'(x_l) \sqcup p_e]) \triangleleft_{\alpha} \mathbf{def}^{\mathbf{O}}(c)) \sqsubseteq_r \Gamma_1}{p \vdash_{\alpha}^{ct} \Gamma \{\text{While e Do c oD } \} \Gamma_1} $$

<caption>Figure 7: Typing Rules for Output Sensitive Constant Time</caption>

disclosures that arise when access to memory is indexed by sensitive information. In order to model the latter category, we shall enrich the simple language from section 2 with arrays:

$$ c ::= x := e \mid x[e_1] := e \mid \mathbf{skip} \mid c_1; c_2 \mid \text{If e then } c_1 \text{ else } c_2 \text{ fi} \mid \text{While e Do c oD} $$

To simplify notations, we assume that array indexes $e_1$ are basic expressions (not referring to arrays) and that $X_O$ does not contain arrays. Moreover as in [4], a state or store $\sigma$ maps array variables $v$ and indices $i \in \mathbb{N}$ to values $\sigma(v, i)$. The labeled semantics of While programs is listed in Figure 6. In all rules, we denote $\vec{f} = (f_i)_i$, the set of all indexes occurring in $e$ (i.e., $e$ contains sub-expressions of the form $x_i[f_i]$).

The labels on the execution steps correspond to the information which is leaked to the environment ($\mathbf{r}$) for a read access on memory, $\mathbf{w}$ for a write access and $\mathbf{b}$ for a branch operation). In the rule for (If), the valuations of branch conditions are leaked. Also, all indexes to program variables read and written at each statement are leaked to. Remark that in cache based attacks, only the offsets are leaked and not the base variable addresses/values. When there is no label on a step, this step is considered to be invisible.

We give in Figure 7 the new typing rules. As above, we denote $\vec{f} = (f_i)_i$, the set of all indexes occurring in $e$. We add a fresh variable $x_l$, that is not used in programs, in order to capture the unintended leakage. Its type is always growing up and it mirrors the information
<table><caption>Figure 8: Instrumentation for $ω(•)$</caption><thead><tr><th>•</th><th>ω(•)</th></tr></thead><tbody><tr><td>x := e</td><td>x<sub>l</sub> := x<sub>l</sub> : r(→f); x := e</td></tr><tr><td>x[e<sub>1</sub>] := e</td><td>x<sub>l</sub> := x<sub>l</sub> : w(e<sub>1</sub>) : r(→f); x[e<sub>1</sub>] := e</td></tr><tr><td>skip</td><td>skip</td></tr><tr><td>c<sub>1</sub>; c<sub>2</sub></td><td>ω(c<sub>1</sub>); ω(c<sub>2</sub>)</td></tr><tr><td>If e then c<sub>1</sub> else c<sub>2</sub> fi</td><td>x<sub>l</sub> := x<sub>l</sub> : b(e) : r(→f); If e then ω(c<sub>1</sub>) else ω(c<sub>2</sub>) fi</td></tr><tr><td>While e Do c oD</td><td>x<sub>l</sub> := x<sub>l</sub> : b(e) : r(→f); While e Do ω(c); x<sub>l</sub> := x<sub>l</sub> : b(e) : r(→f) oD</td></tr></tbody></table>

leaked by each command. In rule (As1") we take a conservative approach and we consider that the type of an array variable is the lub of all its cells. The information leaked by the assignment $x[e_1] := e$ is the index $e_1$ plus the set $\vec{f} = (f_i)_i$ of all indexes occurring in e. Moreover, the new type of the array variable $x$ mirrors the fact that now the value of $x$ depends also on the index $e_1$ and on the right-hand side e.

**Definition 3.1.** An execution trace (or simply trace) is a sequence of visible actions $\xrightarrow{a_1} \xrightarrow{a_2} \dots \xrightarrow{a_n}$, all invisible steps being ignored. A program c is $(X_I, X_O)$-constant time when all its traces starting with $X_I$-equivalent stores that lead to finally $X_O$-equivalent stores, are identical.

Following [4], given a set $X$ of program variables, two stores $\sigma$ and $\rho$ are $X$-equivalent when $\sigma(x, i) = \rho(x, i)$ for all $x \in X$ and $i \in N$. Two traces $\xrightarrow{a_1} \dots \xrightarrow{a_n}$ and $\xrightarrow{b_1} \dots \xrightarrow{b_m}$ are identical iff $n = m$ and $a_j = b_j$ for all $1 \le j \le n$.

We can reduce the $(X_I, X_O)$-constant time security of a command c to the $(X_I, X_O, \{x_l\})$-security (see section 2.7) of a corresponding command $\omega(c)$, obtained by adding a fresh variable $x_l$ to the program variables $fv(c)$, and then adding recursively before each assignment and each boolean condition predicate, a new assignment to the leakage variable $x_l$ that mirrors the leaked information. Let $:b(, )r(, )w(, )$ be some new abstract operators. The construction of the instrumentation $ω(•)$ is shown in Fig. 8. As above, we denote by $\vec{f} = (f_i)_i$ the set of all indexes occurring in e.

First we can extend the While language with array variables, then we need to extend the typing system from section 2 with a rule corresponding to the new rule Ast'. Then, the following lemma gives the relationship between the type of a program c using the new typing system and the type of the instrumented program $\omega(c)$ using the extended typing system from the previous section.

**Lemma 3.2.** Let c a command such that $x_l \notin fv(c)$, $\sigma, \sigma'$ two stores, tr some execution trace and [] the empty trace.

1. $p \vdash_{\alpha}^{ct} \Gamma\{c\}\Gamma'$ iff $p \vdash_{\alpha} \Gamma\{\omega(c)\}\Gamma'$.

2. $(c, \sigma) \stackrel{tr}{\implies} \sigma' \text{ iff } (\omega(c), \sigma[x_l \mapsto []]) \implies \sigma'[x_l \mapsto tr]$.

Now combining Theorem 2.17 and Lemma 3.2 we get the following Theorem which proves the soundness of the new typing system.

**Theorem 3.3.** Let $\mathcal{L}$ be the lattice defined in the section 2.7. Let $(\Gamma, \alpha)$ be defined by $\Gamma(x) = \{\tau_x\}$, for all $x \in \text{Var}$ and $\alpha(o) = \{\tau_o\}$, for all $o \in X_O$ and $\Gamma(x_l) = \perp$. If $p \vdash_{\alpha}^{ct} \Gamma\{c\}\Gamma'$ and $\Gamma'(x_l) \sqsubseteq \Gamma(X_I) \sqcup \alpha(X_O)$, then c is $(X_I, X_O)$-constant time.
<table><caption>Figure 9: Syntax and informal semantics of simplified LLVM-IR</caption><tr><td>r ← op(Op, v̄)</td><td>assign to r the result of Op applied to operands v̄</td></tr><tr><td>r ← load(v)</td><td>load in r the value stored at address pointed by v</td></tr><tr><td>store(v₁, v₂)</td><td>store at address pointed by v₂ the value v₁</td></tr><tr><td>cond(r, b<sub>then</sub>, b<sub>else</sub>)</td><td>branch to b<sub>then</sub> if the value of r is true and to b<sub>false</sub> otherwise</td></tr><tr><td>goto b</td><td>branch to b</td></tr></table>

## 4. APPLICATION TO LOW-LEVEL CODE

We show in this section how the type system we proposed to express output-sensitive constant-time non-interference on the *While* language can be lifted to a low-level program representation like the LLVM byte code [21].

### 4.1. **LLVM-IR.**
We consider a simplified LLVM-IR representation with four instructions: assignments from an expression (register or immediate value) or from a memory block (load), writing to a memory block (store) and (un)conditional jump instructions. We assume that the program control flow is represented by a control-flow graph (CFG) $G = (\mathcal{B}, \rightarrow_E, b_{init}, b_{end})$ where $\mathcal{B}$ is the set of basic blocks, $\rightarrow_E$ the set of edges connecting the basic blocks, $b_{init} \in \mathcal{B}$ the entry point and $b_{end} \in \mathcal{B}$ the ending point. We denote by $Reach(b, b')$ the predicate indicating that node $b'$ is reachable from node $b$, i.e., there exists a path in $G$ from $b$ to $b'$. A program is then a (partial) map from control points $(b, n) \in \mathcal{B} \times \mathbb{N}$ to instructions where each basic block is terminated by a jump instruction. The memory model consists in a set of *registers or temporary variables* $R$ and a set of memory blocks $M$ (including the execution stack). *Val* is the set of values and memory block addresses. The informal semantics of our simplified LLVM-IR is given in Figure 9, where $r \in R$ and $v \in R \cup Val$ is a register or an immediate value.

In the formal operational semantics, execution steps are labeled with leaking data, i.e., addresses of store and load operations and branching conditions. This formal semantics is defined in Figure 10. It is implicitly parameterized by the program $p$, a configuration is a tuple $((b, n), \rho, \mu)$ where $(b, n) \in \mathcal{B} \times \mathbb{N}$ is the control point and $\rho: R \to Val$ (*resp.* $\mu: M \to Val$) denotes the content of registers (*resp.* memory).

### 4.2. **Type system.**
First, we introduce the following notations for an LLVM-IR program represented by a CFG $G = (\mathcal{B}, \rightarrow_E, b_{init}, b_{end})$:

(1) Function $dep: \mathcal{B} \rightarrow 2^B$ associates to each basic block its set of “depending blocks”, i.e., $b' \in dep(b)$ iff $b'$ dominates $b$ and there is no block $b''$ between $b'$ and $b$ such that $b''$ post-dominates $b'$. We recall that a node $b_1$ dominates (*resp.* post-dominates) a node $b_2$ iff every path from the entry node $b_{init}$ to $b_2$ goes through $b_1$ (*resp.* every path from $b_2$ to the ending node $b_{end}$ goes through $b_1$).

(2) Partial function $br: \mathcal{B} \rightarrow R$ returns the “branching register”, i.e., the register $r$ used to compute the branching condition leading outside $b$ ($b$ is terminated by an instruction $cond(r, b_{then}, b_{else})$). Note that in LLVM branching registers are always *fresh* and assigned only once before to be used.

(3) Function $PtsTo: (\mathcal{B} \times \mathbb{N}) \times (R \cup M) \rightarrow 2^M$ returns the set of (addresses of) memory blocks pointed to by a given register or memory block at a given control point. For
$$ \frac{p(b, n) = r \leftarrow op(\overrightarrow{Op}, \overrightarrow{v}) \qquad v = \overline{Op} (\llbracket \overrightarrow{v} \rrbracket_{(\rho, \mu)})}{((b, n), \rho, \mu) \longrightarrow ((b, n+1), \rho[r \rightarrow v], \mu)} $$

$$ \frac{p(b, n) = r \leftarrow load(v) \qquad ad = \llbracket v \rrbracket_{(\rho, \mu)} \qquad val = \mu(ad)}{((b, n), \rho, \mu) \xrightarrow{r(ad)} ((b, n+1), \rho[r \rightarrow val], \mu)} $$

$$ \frac{p(b, n) = goto b' \qquad ((b, n), \rho, \mu) \longrightarrow ((b', 0), \rho, \mu)}{((b, n), \rho, \mu) \longrightarrow ((b', 0), \rho, \mu)} $$

$$ \frac{p(b, n) = store(v_1, v_2) \qquad v = \llbracket v_1 \rrbracket_{(\rho, \mu)} \qquad ad = \llbracket v_2 \rrbracket_{(\rho, \mu)}}{((b, n), \rho, \mu) \xrightarrow{w(ad)} ((b, n+1), \rho, \mu[ad \rightarrow v])} $$

$$ \frac{p(b, n) = cond(r, b_{then}, b_{else}) \qquad \llbracket r \rrbracket_{(\rho, \mu)} = 1}{((b, n), \rho, \mu) \xrightarrow{j(1)} ((b_{then}, 0), \rho, \mu)} $$

$$ \frac{p(b, n) = cond(r, b_{then}, b_{else}) \qquad \llbracket r \rrbracket_{(\rho, \mu)} = 0}{((b, n), \rho, \mu) \xrightarrow{j(0)} ((b_{else}, 0), \rho, \mu)} $$

<caption>Figure 10: Labeled operational semantics for LLVM-IR</caption>

example, $bl \in PtsTo(b, n)(r)$ means that at control point $(b, n)$, register $r$ may contain the address of block $bl \in M$.

We now define a type system (Figures 11 to 14) that allows to express the output-sensitive constant-time property for LLVM-IR-like programs. The main difference with respect to the rules given at the source level (Figures 4 and 7) is that the control-flow is explicitly given by the CFG, and not by the language syntax. For a LLVM-like program, an environment $\Gamma: R \cup M \mapsto \mathcal{L}$, associates security types to registers and memory blocks. We will use the notation $\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma'$ inspired from the one used by [6]. The intuitive meaning of this judgement is the following: if $I$ is the instruction of control point $(b, n)$ and $\tau_0$ is the join of all the types of the branching conditions dominating the current basic block $b$ then $\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma'$ is equivalent to the notation $\tau_0 \vdash_{\alpha} \Gamma\{I\}\Gamma'$ used in section 2.4, that is, it transforms the previous environment $\Gamma$ into the new environment $\Gamma'$.

**Assignment from an operation Op (Figure 11).** In rules Op1 and Op2, the new type $\tau$ of the assigned register $r$ is the join of the type of operands $\overrightarrow{v}$ and the type of all the branching conditions dominating the current basic block ($\tau_0$). Note that since branching registers $r$ are assigned only once in LLVM there is no need to update their dependencies from output variables (using the $\langle\alpha$ operator), $\Gamma(r)$ being never changed once $r$ has been assigned.
$$ \begin{array}{l} p(b, n) = r \leftarrow op(\overrightarrow{Op}, \vec{v}) \qquad \tau = (\Gamma[\alpha](\vec{v}) \sqcup \tau_0) \\ \tau_0 = \bigsqcup_{x \in br dep(b)} \Gamma[\alpha](x) \qquad r \notin X_O \\ \text{Op1} \frac{}{\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma[r \to \tau]} \end{array} $$

$$ \begin{array}{l} p(b, n) = r \leftarrow op(\overrightarrow{Op}, \vec{v}) \qquad \tau = (\Gamma[\alpha](\vec{v}) \sqcup \tau_0) \\ \tau_0 = \bigsqcup_{x \in brdep(b))} \Gamma[\alpha](x) \qquad \Gamma_1 = \Gamma \lhd_{\alpha} r \\ \text{Op2} \frac{}{\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma_1[r \to \tau]} \end{array} $$

<caption>Figure 11: assignment from an operation Op</caption>

$$ \begin{array}{l} p(b, n) = r \leftarrow load(v) \qquad A_m = PtsTo(b, n)(v) \qquad r \notin X_O \\ \tau_0 = \bigsqcup_{x \in br dep(b))} \Gamma[\alpha](x) \qquad \tau_1 = \Gamma[\alpha](v) \sqcup \tau_0 \qquad \tau_2 = \Gamma[\alpha](A_m) \\ \text{Ld1} \frac{}{\vdash_{\alpha} (b, n) : \Gamma \Rightarrow (\Gamma[x_l \to \Gamma(x_l) \sqcup \tau_1][r \to \tau_2 \sqcup \tau_1]}} \end{array} $$

$$ \begin{array}{l} p(b, n) = r \leftarrow load(v) \qquad A_m = PtsTo(b, n)(v) \qquad r \in X_O \\ \tau_0 = \bigsqcup_{x \in br dep(b))} \Gamma_1[\alpha](x) \qquad \tau_1 = \Gamma_1[\alpha](v) \sqcup \tau_0 \qquad \tau_2 = \Gamma_1[\alpha](A_m) \\ \text{Ld2} \frac{}{\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma_1[x_l \to \Gamma_1(x_l) \sqcup \tau_1][r \to \tau_2 \sqcup \tau_1]} \end{array} $$

<caption>Figure 12: assignment from a load expression</caption>

**Assignment from a load expression (Figure 12).** Rules Ld1 and Ld2 update $\Gamma$ in a similar way as Op1 and Op2, the main difference being that since some of the memory locations accessed when dereferencing $v$ (i.e., $PtsTo(b, n)(v)$) are in $A_m$ (i.e., potentially in the cache) the dependencies of $v$ are added to the type of the leakage variable $x_l$.

$$ \begin{array}{l} p(b, n) = store(v_1, v_2) \qquad A_m = PtsTo(b, n)(v_2) \\ \tau_0 = \bigsqcup_{x \in br dep(b))} \Gamma[\alpha](x) \qquad A_0 = A_m \cap X_0 \qquad \Gamma_1 = \Gamma \lhd_{\alpha} A_0 \\ \qquad \tau_1 = \Gamma_1[\alpha](v_2) \sqcup \tau_0 \qquad \tau_2 = \Gamma_1[\alpha](v_1) \\ \text{St} \frac{}{\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma_1[x_l \to \Gamma_1(x_l) \sqcup \tau_1][v_{s \in A_m} \to \Gamma(v_s) \sqcup \tau_2 \sqcup \tau_1]} \end{array} $$

<caption>Figure 13: store instruction</caption>

**Store instruction (Figure 13).** Rule St updates the dependencies of all memory locations pointed to by $v_2$ by adding the types of $v_1$ and $v_2$ itself. In addition, the type of the leakage
variable $x_l$ is also updated with the dependencies of $v_2$ and with the dependencies of all branching registers that influenced the execution flow to reach the current block b.

$$ \text{CJmp} \frac{p(b, n) = \text{cond}(r, b_{\text{then}}, b_{\text{else}})}{\vdash_{\alpha} (b, n) : \Gamma \Rightarrow \Gamma[x_l \rightarrow \Gamma(x_l) \sqcup \Gamma[\alpha](r)]} $$

<caption>Figure 14: conditional and unconditional jump</caption>

**Conditional and unconditional jump (Figure 14).** Rule CJmp indicates that the leakage variable type is augmented with the type of the branching condition register. Unconditional jumps (Rule Jmp) leave the environment unchanged.

**4.3. Well typed LLVM programs are output-sensitive constant-time.** The following definition is adapted from [6].

**Definition 4.1.** An LLVM-IR program $p$ is well typed with respect to an initial environment $\Gamma_0$ and final environment $\Gamma'$ (written $\vdash_{\alpha} p : \Gamma_0 \Rightarrow \Gamma'$), if there is a family of well-defined environments $\{(\Gamma)_{(b,n)} | (b,n) \in (\mathcal{B}, \mathbb{N})\}$, such that for all nodes $(b, n)$ and all its successors $(b', n')$, there exists a type environment $\gamma$ and $A \subseteq X_O$ such that

$$ \vdash_{\alpha} (b, n) : \Gamma_{(b,n)} \Rightarrow \gamma \text{ and } (\gamma \prec_{\alpha} A) \sqsubseteq_{r} \Gamma_{(b',n')}. $$

In the above definition the set $A$ is mandatory in order to prevent dependency cycles between variables in $X_O$.

The following Theorem is the counterpart of Theorem 3.3. It shows the soundness of our type system for LLVM-IR programs with respect to output-sensitive constant-time.

**Theorem 4.2.** Let $\mathcal{L}$ be the lattice from the section 2.7. Let $(\Gamma, \alpha)$ be defined by $\Gamma(x) = \{\tau_x\}$, for all $x \in R \cup M$, $\alpha(o) = \{\tau_o\}$, for all $o \in X_O$ and $\Gamma(x_l) = \perp$. If $\vdash_{\alpha} p : \Gamma \Rightarrow \Gamma'$ and $\Gamma'(x_l) \subseteq \Gamma(X_I) \sqcup \alpha(X_O)$, then $p$ is $(X_I, X_O)$- constant time.

**4.4. Example.** We illustrate below the effect of the LLVM-IR typing rules on a short example. The C code of this example is given on Figure 15, and the corresponding (simplified) LLVM-IR on Figure 16.

```c
int p[10], q[10]; // global variables

int main () {
    int x, y;
    p[x] = q[y];
    return 0; // output value is always 0
}
```

<caption>Figure 15: A C code example</caption>

In LLVM-IR, instructions `alloca` and `global` allow to declare temporary and global variables and their value correspond to memory addresses. For a sake of simplicity we choose
1 @q = **common** global

2 @p = **common** global

3 %x = **alloca** i32

4 %y = **alloca** i32

5

6 %1 = **load** i32 * %y

7 %2 = **getelementptr** @q, 0, %1

8 %3 = **load** %2

9 %4 = **load** %x

10 %5 = **getelementptr** @p, 0, %4

11 **store** %3, %5

<caption>Figure 16: The simplified LLVM-IR code of Figure 15</caption>

to not define specific typing rules for these instructions, they are taken into account only in
building the initial environment.

First, we assume that $x_l$ denotes the *leakage* variable and that the content of C variables
$p, q, x$ and $y$ are stored in memory blocks $b_0$ to $b_3$, i.e. at the initial control point,
$\text{PtsTo}(@p) = b_0, \text{PtsTo}(@q) = b_1, \text{PtsTo}(\%x) = b_2, \text{PtsTo}(\%y) = b_3$.

Now we consider the following initial environment (produced by lines 1-4 in Figure 16):
$\Gamma_0(@p) = \Gamma_0(@q) = \Gamma_0(\%x) = \Gamma_0(\%y) = \perp$
$\Gamma_0(b_0) = P, \Gamma_0(b_1) = Q, \Gamma_0(b_2) = X, \Gamma_0(b_3) = Y, \Gamma_0(x_l) = \perp$

This initial environment captures the idea that the values of variables @p, @q, %x, %y
are addresses (of memory blocks corresponding to the “high-level” C variables p, q, x and
y) and hence their security type is ⊥, and the memory blocks b₀ to b₃ correspond to the C
variables p, q, x and y, and this is mirrored in the initial environment Γ₀. Moreover, initially,
nothing is leaked yet.

We then update Γ₀ by applying our typing rules in sequence to each instruction of the
LLVM-IR representation. Note that the **getelementptr** instruction, which is specific to
LLVM, allows to compute an address corresponding to an indexed access in a buffer. Hence,
it is treated by our typing system as an arithmetic (*Op*) instruction.

%1 = **load** %y

$$
\begin{align*}
\Gamma_1 &= \Gamma_0[x_l \rightarrow \Gamma_0(x_l) \sqcup \Gamma_0(\%y), \%1 \rightarrow \Gamma_0(\%y) \sqcup \Gamma_0(\text{PtsTo}(\%y))] \\
&= \Gamma_0[x_l \rightarrow \perp, \%1 \rightarrow Y]
\end{align*}
$$

%2 = **getelementptr** @q, 0, %1

$$
\text{PtsTo}(\%2) = b_1
$$

$$
\begin{align*}
\Gamma_2 &= \Gamma_1[\%2 \rightarrow \Gamma_1(@q) \sqcup \Gamma_1(0) \sqcup \Gamma_1(\%1)] \\
&= \Gamma_1[\%2 \rightarrow Y]
\end{align*}
$$

%3 = **load** %2

$$
\begin{align*}
\Gamma_3 &= \Gamma_2[x_l \rightarrow \Gamma_2(x_l) \sqcup \Gamma_2(\%2), \%3 \rightarrow \Gamma_0(\%2) \sqcup \Gamma_0(\text{PtsTo}(\%2))] \\
&= \Gamma_2[x_l \rightarrow Y, \%3 \rightarrow Y \sqcup Q]
\end{align*}
$$
%4 = load %x

$$
\begin{align*}
\Gamma_4 &= \Gamma_3[x_l \rightarrow \Gamma_3(x_l) \sqcup \Gamma_3(\%x), \%4 \rightarrow \Gamma_3(\%x) \sqcup \Gamma_3(\text{PtsTo}(\%x))] \\
&= \Gamma_3[\%4 \rightarrow X]
\end{align*}
$$

%5 = getelementptr @p, 0, %4

$$
\begin{align*}
\text{PtsTo}(\%5) &= b_0 \\
\Gamma_5 &= \Gamma_4[\%5 \rightarrow \Gamma_4(@p) \sqcup \Gamma_4(0) \sqcup \Gamma_4(\%4)] \\
&= \Gamma_4[\%5 \rightarrow X]
\end{align*}
$$

store %3, %5

$$
\begin{align*}
\Gamma_6 &= \Gamma_5[x_l \rightarrow \Gamma_5(x_l) \sqcup \Gamma_5(\%5), \text{PtsTo}(\%5) \rightarrow \Gamma_5(\text{PtsTo}(\%5)) \sqcup \Gamma_5(\%3) \sqcup \Gamma_5(\%5)] \\
&= \Gamma_5[x_l \rightarrow Y \sqcup X, b_0 \rightarrow P \sqcup Y \sqcup Q \sqcup X]
\end{align*}
$$

Making all the replacements, we get that the final environment is:

$$
\Gamma_6 = [x_l \to Y \sqcup X, b_0 \to P \sqcup Y \sqcup Q \sqcup X, b_1 \to Q, b_2 \to X, b_3 \to Y, @p \to \bot, @q \to \bot, \\
\%x \to \bot, \%y \to \bot, \%1 \to Y, \%2 \to Y, \%3 \to Y \sqcup Q, \%4 \to X, \%5 \to X]
$$

In this final environment Γ₆, variable xₗ depends on the initial types X and Y assigned to memory blocks b₂ and b₃. This means that the addresses accessed when reading (resp. writing) buffer p (resp. q) may leak to an attacker. Hence, if one of the variables x or y is a secret, since neither x nor y is an output value, then this program is not output sensitive constant-time, which may lead to a security issue.

4.5. **Implementation.** We are developing a prototype tool implementing the type system for LLVM programs. This type system consists in computing flow-sensitive dependency relations between program variables. Def. 4.1 provides the necessary conditions under which the obtained result is sound (Theorem 4.2). We give some technical indications regarding our implementation.

Output variables $X_O$ are defined as function return values and global variables; we do not currently consider arrays nor pointers in $X_O$. Control dependencies cannot be deduced from the syntactic LLVM level, we need to explicitly compute the dominance relation between basic blocks of the CFG (the *dep* function). Def. 4.1 requires the construction of a set $A \subseteq X_O$ to update the environment produced at each control locations in order to avoid circular dependencies (when output variable are assigned in *alternative* execution paths). To identify the set of basic blocks belonging to such alternative execution paths leading to a given block, we use the notion of *Hammock regions* [15]. More precisely, we compute function *Reg*: $(\mathcal{B} \times \mathcal{B} \times (\rightarrow_E)) \rightarrow 2^{\mathcal{B}}$, returning the set of *Hammock regions* between a basic block *b* and its immediate dominator *b'* with respect to an incoming edge *e*ᵢ of *b*. Thus, *Reg*(*b'*, *b*, (*c*, *b*)) is the set of blocks belonging to CFG paths going from *b'* to *b* without reaching edge *e*ᵢ = (*c*, *b*): *Reg*(*b'*, *b*, (*c*, *b*)) = {*b*ᵢ | *b'*ᵢ → *E*, *b*₁ ... → *E*, *b*ₙ → *E*, *b* ∧ ∀i ∈ [1, n − 1]. ¬*Reach*(*b*ᵢ, *c*)}. Fix-point computations are implemented using Kildall’s algorithm. To better handle real-life examples we are currently implementing the *PtsTo* function, an inter-procedural analysis, and a more precise type analysis combining both over- and under-approximations of variable dependencies (see section 6).
## 5. RELATED WORK

**Information flow.** There is a large number of papers on language-based security aiming to prevent undesired information flows using type systems (see [27]). An information-flow security type system statically ensures noninterference, i.e. that sensitive data may not flow directly or indirectly to public channels [31, 24, 30, 29]. The typing system presented in section 2 builds on ideas from Hunt and Sands'

As attractive as it is, noninterference is too strict to be useful in practice, as it prevents confidential data to have any influence on observable, public output: even a simple password checker function violates noninterference. Relaxed definitions of noninterference have been defined in order to support such intentional downward information flows [28]. Li and Zdancewic [22] proposed an expressive mechanism called *relaxed noninterference* for declassification policies that supports the extensional specification of secrets and their intended declassification. A declassification policy is a function that captures the precise information on a confidential value that can be *declassified*. For the password checker example, the following declassification policy $\lambda p.\lambda x.h(p) == x$, allows an equality comparison with the hash of password to be declassified (and made public), but disallows arbitrary declassifications such as revealing the password.

The problem of information-flow security has been studied also for low level languages. Barthe and Rezk [8, 9] provide a flow sensitive type system for a sequential bytecode language. As it is the case for most analyses, implicit flows are forbidden, and hence, modifications of parts of the environment with lower security type than the current context are not allowed. Genaim and Spoto present in [16] a compositional information flow analysis for full Java bytecode.

**Information flow applied to detecting side-channel leakages.** Information-flow analyses track the flow of information through the program but often ignore information flows through side channels. Side-channel attacks extract sensitive information about a program's state through its observable use of resources such as time or memory. Several approaches in language-based security use security type systems to detect timing side-channels [1, 18]. Agat [1] presents a type system sensitive to timing for a small While-language which includes a transformation which takes a program and transforms it into an equivalent program without timing leaks. Molnar et al [23] introduce the program counter model, which is equivalent to path non-interference, and give a program transformation for making programs secure in this model.

FlowTracker [26] allows to statically detect time-based side-channels in LLVM programs. Relying on the assumption that LLVM code is in SSA form, they compute control dependencies using a sparse analysis [13] without building the whole Program Dependency Graph. Leakage at assembly-level is also considered in [6]. They propose a fine-grained information-flow analysis for checking that assembly programs generated by CompCert are constant-time. Moreover, they consider a stronger adversary which controls the scheduler and the cache.

All the above works do not consider publicly observable outputs. The work that is closest to ours is [4], where the authors develop a formal model for constant-time programming policies. The novelty of their approach is that it is distinguishing not only between public and private input values, but also between private and publicly observable output values. As they state, this distinction poses interesting technical and theoretical challenges. Moreover,
constant-time implementations in cryptographic libraries like OpenSSL include optimizations
for which paths and addresses can depend not only on public input values, but also on
publicly observable output values. Considering only input values as non-secret information
would thus incorrectly characterize those implementations as non-constant-time. They also
develop a verification technique based on the self-composition based approach [7]. They
reduce the constant time security of a program P to safety of a product program Q that
simulates two parallel executions of P. The tool operates at the LLVM bytecode level. The
obtained bytecode program is transformed into a product program which is verified by the
Boogie verifier [5] and its SMT tool suite. Their approach is complete only if the public
output is ignored. Otherwise, their construction relies on identifying the branches whose
conditions can only be declared benign when public outputs are considered. For all such
branches, the verifier needs to consider separate paths for the two simulated executions,
rather than a single synchronized path and in the worst case this can deteriorate to an
expensive product construction.

6. CONCLUSION AND PERSPECTIVES

In this paper we proposed a static approach to check if a program is output-sensitive
constant-time, i.e., if the leakage induced through branchings and/or memory accesses do
not overcome the information produced by (regular) observable outputs. Our verification
technique is based on a so-called output-sensitive non-interference property, allowing to
compute the dependencies of a leakage variable from both the initial values of the program
inputs and the final values of its outputs. We developed a type system on a high-level **While**
language, and we proved its soundness. Then we lifted this type system to a basic LLVM-IR
and we developed a prototype tool operating on this intermediate representation, showing
the applicability of our technique.

This work could be continued in several directions. One limitation of our method
arising in practice is that even if the two snippets $x_l = h$; $o = h$ and $o = h$; $x_l = o$ are
equivalent, only the latter can be typed by our typing system. We are currently extending
our approach by considering also an under-approximation $\beta(\bullet)$ of the dependencies between
variables and using "symbolic dependencies" also for non-output variables. Then the
safety condition from Theorem 2.17 can be improved to something like "$\exists V$ such that
$(\Gamma'(x_l) \triangleleft_\alpha V) \sqsubseteq (\Gamma(X_I) \triangleleft_\alpha V) \sqcup (\beta'(X_O) \triangleleft_\alpha V) \sqcup \alpha(X_O)$". In the above example, we
would obtain $\Gamma'(x_l) = \alpha(h) = \beta'(o) \sqsubseteq \alpha(o) \sqcup \beta'(o)$, meaning that the unwanted maximal
leakage $\Gamma'(x_l)$ is less than the minimal leakage $\beta'(o)$ due to the normal output. From the
implementation point of view, further developments are needed in order to extend our
prototype to a complete tool able to deal with real-life case studies. This may require
to refine our notion of arrays and to take into account arrays and pointers as output
variables. We could also consider applying a sparse analysis, as in FlowTracker [26]. It may
happen that such a pure static analysis would be too strict, rejecting too much "correct"
implementations. To solve this issue, a solution would be to combine it with the dynamic
verification technique proposed in [4]. Thus, our analysis could be used to find automatically
which branching conditions are benign in the output-sensitive sense, which could reduce the
product construction of [4]. Finally, another interesting direction would be to adapt our
work in the context of quantitative analysis for program leakage, like in [14].
ACKNOWLEDGMENT

The authors wish to acknowledge the anonymous referees for their fruitful comments and
suggestions.

REFERENCES

[1] Agat, J.: Transforming out timing leaks. In: Proceedings of the 27th ACM SIGPLAN-SIGACT symposium on Principles of programming languages. pp. 40–53. ACM (2000)

[2] Al Fardan, N.J., Paterson, K.G.: Lucky thirteen: Breaking the tls and dtls record protocols. In: Security and Privacy (SP), 2013 IEEE Symposium on. pp. 526–540. IEEE (2013)

[3] Albrecht, M.R., Paterson, K.G.: Lucky microseconds: A timing attack on amazon's s2n implementation of tls. In: Annual International Conference on the Theory and Applications of Cryptographic Techniques. pp. 622–643. Springer (2016)

[4] Almeida, J.B., Barbosa, M., Barthe, G., Dupressoir, F., Emmi, M.: Verifying constant-time implementations. In: 25th USENIX Security Symposium (USENIX Security 16). pp. 53–70. USENIX Association, Austin, TX (2016), https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/almeida

[5] Barnett, M., Chang, B.Y.E., DeLine, R., Jacobs, B., Leino, K.R.M.: Boogie: A modular reusable verifier for object-oriented programs. In: FMCO. vol. 5, pp. 364–387. Springer (2005)

[6] Barthe, G., Betarte, G., Campo, J., Luna, C., Pichardie, D.: System-level non-interference for constant-time cryptography. In: Proceedings of the 2014 ACM SIGSAC Conference on Computer and Communications Security. pp. 1267–1279. ACM (2014)

[7] Barthe, G., D'Argenio, P.R., Rezk, T.: Secure information flow by self-composition. In: Computer Security Foundations Workshop, 2004. Proceedings. 17th IEEE. pp. 100–114. IEEE (2004)

[8] Barthe, G., Rezk, T.: Secure information flow for a sequential java virtual machine. In: TLDI'05: Types in Language Design and Implementation. Citeseer (2003)

[9] Barthe, G., Rezk, T., Basu, A.: Security types preserving compilation. Computer Languages, Systems & Structures **33**(2), 35–59 (2007)

[10] Bernstein, D., Lange, T., Schwabe, P.: The security impact of a new cryptographic library. Progress in Cryptology–LATINCRYPT 2012 pp. 159–176 (2012)

[11] Blazy, S., Pichardie, D., Trieu, A.: Verifying constant-time implementations by abstract interpretation. In: European Symposium on Research in Computer Security. pp. 260–277. Springer (2017)

[12] Brumley, D., Boneh, D.: Remote timing attacks are practical. Computer Networks **48**(5), 701–716 (2005)

[13] Choi, J.D., Cytron, R., Ferrante, J.: Automatic construction of sparse data flow evaluation graphs. In: Proceedings of the 18th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages. pp. 55–66. POPL '91, ACM (1991)

[14] Doychev, G., Köpf, B., Mauborgne, L., Reineke, J.: Cacheaudit: A tool for the static analysis of cache side channels. ACM Trans. Inf. Syst. Secur. **18**(1), 4:1–4:32 (Jun 2015). https://doi.org/10.1145/2756550, http://doi.acm.org/10.1145/2756550

[15] Ferrante, J., Ottenstein, K., Warren, J.: The program dependence graph and its use in optimization. TOPLAS **9**(3), 319–349 (1987)

[16] Genaim, S., Spoto, F.: Information flow analysis for java bytecode. In: Verification, Model Checking, and Abstract Interpretation. pp. 346–362. Springer (2005)

[17] Gullasch, D., Bangerter, E., Krenn, S.: Cache games–bringing access-based cache attacks on aes to practice. In: Security and Privacy (SP), 2011 IEEE Symposium on. pp. 490–505. IEEE (2011)

[18] Hedin, D., Sands, D.: Timing aware information flow security for a javacard-like bytecode. Electronic Notes in Theoretical Computer Science **141**(1), 163–182 (2005)

[19] Hunt, S., Sands, D.: Binding time analysis: A new perspective. In: In Proceedings of the ACM Symposium on Partial Evaluation and Semantics-Based Program Manipulation (PEPM'91). pp. 154–164. ACM Press (1991)

[20] Hunt, S., Sands, D.: On flow-sensitive security types. In: ACM SIGPLAN Notices. vol. 41, pp. 79–90. ACM (2006)
[21] Lattner, C., Adve, V.: Llvm: A compilation framework for lifelong program analysis & transformation. In: Proceedings of the International Symposium on Code Generation and Optimization: Feedback-directed and Runtime Optimization. CGO '04, IEEE Computer Society, Washington, DC, USA (2004)

[22] Li, P., Zdancewic, S.: Downgrading policies and relaxed noninterference. In: Proceedings of POPL. vol. 40, pp. 158–170. ACM (2005)

[23] Molnar, D., Piotrowski, M., Schultz, D., Wagner, D.: The program counter security model: Automatic detection and removal of control-flow side channel attacks. In: ICISC. vol. 3935, pp. 156–168. Springer (2005)

[24] Myers, A.C.: Jflow: Practical mostly-static information flow control. In: Proceedings of the 26th ACM SIGPLAN-SIGACT symposium on Principles of programming languages. pp. 228–241. ACM (1999)

[25] Nation, J.B.: Notes on lattice theory (1998)

[26] Rodrigues, B., Quintão Pereira, F.M., Aranha, D.F.: Sparse representation of implicit flows with applications to side-channel detection. In: Proceedings of the 25th International Conference on Compiler Construction. pp. 110–120. ACM (2016)

[27] Sabelfeld, A., Myers, A.C.: Language-based information-flow security. IEEE Journal on selected areas in communications **21**(1), 5–19 (2003)

[28] Sabelfeld, A., Sands, D.: Declassification: Dimensions and principles. Journal of Computer Security **17**(5), 517–548 (2009)

[29] Swamy, N., Chen, J., Chugh, R.: Enforcing stateful authorization and information flow policies in fine. In: ESOP. pp. 529–549. Springer (2010)

[30] Vaughan, J.A., Zdancewic, S.: A cryptographic decentralized label model. In: Security and Privacy, 2007. SP’07. IEEE Symposium on. pp. 192–206. IEEE (2007)

[31] Volpano, D., Irvine, C., Smith, G.: A sound type system for secure flow analysis. Journal of computer security **4**(2-3), 167–187 (1996)