<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% flag to use fancy fonts / graphics 
\newif\ifjnf\jnftrue

\documentclass[11pt]{article}

\usepackage{tikz} \usetikzlibrary{arrows} \usepackage{cmtt}
\usepackage{amsmath} \usepackage{amssymb} \usepackage{amsthm}
\usepackage{url} \usepackage{xspace} \usepackage[margin=1in]{geometry}

\usepackage{csnotes}

\newcommand{\pic}{$\pi$-calculus\xspace}

\begin{document}

\header{6 October 2011}{Jean-Baptiste Jeannin}

Today we will see two different kinds of type systems for the
\pic. After quickly reviewing the simply typed languages, we will move
on to the \pic. In the \pic, we will add in a channel action, which
has two actions, read and write, as well as sub-typing relations. In a
second part of the lecture, we will see session types, and use process
calculi types.

The reading for today was \emph{Secure Implementations for Typed
Session Abstractions}, by R. Corin, P.M. Denielou, C. Fournet,
K. Bhargavan, and J. Leifer, published in CSF'07, and available at
available at \url{http://dx.doi.org/10.1109/CSF.2007.29}. Throughout
this lecture we will follow a deck of slides on the typed \pic by
Francesco Zappa Nardelli, available at
\url{http://moscova.inria.fr/~zappa/teaching/mpri/2006/pitypes.pdf}.

In sequential languages, types are mainly used to detect simple
programming errors at compilation time. They allow to detect that some
expressions make no sense, and thus reject them. They are also useful
to optimize compilers or reason about programs.

\section{Simply-typed \pic}

In the \pic so far, the only values are names. We now extend the \pic
with base values of types {\tt int} and {\tt bool}, and with
tuples. Now we can write terms which make no sense, like trying to add
with a boolean:
$$\bar{x}\langle {\sf true} \rangle.P\ ||\ x(y).\bar z(y+1)$$
or even worse, trying to receive a channel, but instead receiving a
bool:
$$\bar{x}\langle{\sf true}\rangle.P\ ||\ x(y).\bar y(4)$$

These terms raise runtime errors; here a runtime exception is
raised. Typing is about preventing runtime errors. To do so and as
usual, we perform some simple static analysis before we run the
program.  Names are values which denote channels. But in the term
$\bar x\langle 3\rangle.P'$, what should the type of $x$ be? The idea
is to state that $x$ should be a channel that can transport values of
type {\tt int}. We introduce a parameterized type constructor {\sf ch}
and write:
$$x:{\sf ch}({\tt int})$$

\subsection{Syntax, semantics and type system} The syntax of types
$T$, messages $M$ and processes $P$ is given by:
$$T\ ::=\ {\sf ch}(T)\ |\ T\times T\ |\ {\tt unit}\ |\ {\tt int}\ |\
{\tt bool}$$
$$M\ ::=\ x\ |\ (M,M)\ |\ ()\ |\ 1,2,\ldots\ |\ {\tt true}\ |\ {\tt false}$$
$$P\ ::=\ {\bf 0}\ |\ x(y:T).P\ |\ \bar x\langle M\rangle.P\ |\ P||P\
|\ (\nu x:T)P\ |\ {\sf match}\ z\ {\sf with}\ (x:T_1,y:T_2)\ {\sf in}\
P\ |\ !P$$

It is a small variation on the \pic we have seen so far: we have
annotated with a type any bound variable on a receive, and any new
variable

The type environments are $\Gamma\ ::=\ \emptyset\ |\ \Gamma,x:T$, and
typing judgments are:
\begin{itemize}
\item $\Gamma\vdash M:T$, meaning that value $M$ has type $T$ under
the environment $\Gamma$;
\item $\Gamma\vdash P$, meaning that process $P$ respects the type
assignment $\Gamma$.
\end{itemize}

The typing rules are pretty simple and are in the slides. The
interesting ones are:
$$
\begin{array}{ccc} \displaystyle\frac{\Gamma,x:T\vdash
P}{\Gamma\vdash(\nu x:T)P}\qquad \displaystyle\frac{\Gamma\vdash
x:{\sf ch}(T)\quad\Gamma,y:T\vdash P}{\Gamma\vdash x(y:T).P}\qquad
\displaystyle\frac{\Gamma\vdash x:{\sf ch}(T)\quad\Gamma\vdash
M:T\quad\Gamma:P}{\Gamma\vdash\bar x\langle M\rangle.P}
\end{array}
$$

The simply-typed \pic makes every single process terminate. We need to
have a more complicated type system for Turing completeness.

\subsection{Soundness}

Type soundness of the type system can be proved along the lines of
Wright and Felleisen's syntactic approach to type soundness: proving
progress and preservation guarantees that the system will not
encounter any type error.

We extend the syntax with a special expression {\tt wrong}, that is a
normal form but not a value, and show that {\tt wrong} can never occur
in a well-typed system. Adding the {\tt wrong} statement can be a huge
pain, since you need to add it to each one of your operational
semantics terms. If you have run down to a value (e.g., {\bf 0}), you
do not have to show that it can take a step (progress lemma).

\subsection{Sub-typing} We separate the channel type into two different
capabilities:
\begin{itemize}
\item $i(T)$ input (read) capability
\item $o(T)$ output (write) capability
\end{itemize} A channel without annotation can do both inputs and
outputs. This forms a basis for sub-typing on channels.

As usual with sub-typing, the directionality is bizarre, for example:
$$x:o(o(T))\vdash (\nu y:{\sf ch}(T))\bar x\langle y\rangle.!y(z:T)$$
is well-typed, because ${\sf ch}(T)&lt;:o(T)$. If channel $x$ is a type
that sends output channels that sends output channels that send $T$,
then a new $y$ of ${\sf ch}(T)$ can be sent on $x$, and then values of
type $T$ can be sent on it.

Formally, the sub-typing relation is a preorder (it is reflexive and
transitive), and capabilities can be forgotten:
$$
{\sf ch}(t)&lt;:i(T) \qquad\qquad {\sf ch}(t)&lt;:o(T)
$$
$i$ is a covariant type constructor, $o$ is contravariant, and ${\sf
ch}$ is invariant:
$$
\frac{T_1&lt;:T_2}{i(T_1)&lt;:i(T_2)}\qquad
\frac{T_2&lt;:T_1}{o(T_1)&lt;:o(T_2)}\qquad \frac{T_2&lt;:T_1\quad
T_1&lt;:T_2}{{\sf ch}(T_1)&lt;:{\sf ch}(T_2)}
$$
$i$ needs to be covariant because if ints are a subtype of reals, it
means that we can receive ints and then use them as reals, so an input
channel for ints should be a subtype of an input channel for
reals. $o$ needs to be contravariant, because it is always OK to use
an output channel expecting reals when you have an output channel
expecting ints, since the process on the other side can use the ints
you give it as reals. The invariant nature of $i$ and contravariant
nature of $o$ leads to the invariant nature of ${\sf ch}$.

\begin{example}\ \\ $\nu(a:{\sf ch}({\sf ch}({\tt int})),x:{\sf
ch}({\tt int}))(\\\bar a\langle x\rangle\ ||\\a(x:i({\tt int}).P\
||\\a(x:o({\tt int}).Q)) )$
\end{example}

Finally, we need to update the typing rules as in:
$$
\frac{\Gamma\vdash x:i(T)\quad\Gamma,y:T\vdash P}{\Gamma\vdash
x(y:T).P}\qquad \frac{\Gamma\vdash x:o(T)\quad\Gamma\vdash
M:T\quad\Gamma:P}{\Gamma\vdash\bar x\langle M\rangle.P}\qquad
\frac{\Gamma\vdash M:T_1\quad T_1&lt;: T_2}{\Gamma\vdash M:T_2}
$$

\subsection{Types for reasoning}

A type is a contract between a process and its environment. The
environment must respect the constraints imposed by the typing
discipline. Is is only possible to plug in a process into a context
where the contracts will not be violated.

Thus we might only have to consider the well-typed contexts for
congruence relations from last time. This makes it easier to show that
two processes are the same, it reduces the number of legal contexts,
and gives us more process equalities.

We now get the typed versions of all the equivalence relations we have
played with in this course so far. Informally, we say that processes
$P$ and $Q$ are equivalent in $\Gamma$, and we write $P\cong_\Gamma
Q$, if and only if $\Gamma\vdash P,Q$, and they are equivalent in all
the testing contexts that respect the types in $\Gamma$.

Now they are processes we were able to distinguish in the untyped \pic
but cannot in the typed \pic, for example:
$$
P=(\nu x)\bar a\langle x\rangle.\bar x\langle\rangle \qquad Q=(\nu
x)\bar a\langle x\rangle.{\bf 0}
$$
This is because under $\Gamma= a:{\sf ch}(o({\tt unit}))$, the
residual $\bar x\langle\rangle$ is deadlocked in all situations.

Another example is given by the specification and implementation of
the factorial function:
\begin{align*} {\sf Spec} &amp;= !f(x,r).\bar r\langle{\sf
fact}(x)\rangle\\ {\sf Imp} &amp;= !f(x,r).{\tt if}\ x=0\ {\tt then} \bar
r\langle 1\rangle\ {\tt else}\ (\nu r')\bar f\langle
x-1,r'\rangle.r'(m).\bar r\langle x*m\rangle
\end{align*} In general ${\sf Spec}\not\cong{\sf Imp}$, because $f$ is
not private, therefore some other process could intercept it. This is
solved with i/o types, which make it possible to ensure that the $f$
channel is only ever used as an output.

Everything weâ€™ve done about reasoning about systems can be done in a
typed domain.

\section{Session types} This discussion on session types is based on
\emph{Secure Implementations for Typed Session Abstractions}, by
R. Corin, P.M. Denielou, C. Fournet, K. Bhargavan, and J. Leifer,
published in CSF'07, and available at available at
\url{http://dx.doi.org/10.1109/CSF.2007.29}. Slides are available at
\url{http://msr-inria.inria.fr/projects/sec/sessions/slides.pdf}.

The idea is to use the \pic like a syntax to describe protocols. They
use the \pic sessions to make a compiler such that, no matter what
happens in the distributed system, the protocol is not violated. Even
if the attacker takes over some subset of the nodes, he will not be
able to interfere with the protocol. The worst the attacker could do
is keeping any messages from going out.

They propose a general purpose language for expressing distributed
systems with session types, where the compiler guarantees certain
properties of the system, and where channel actions cannot just be
sent naively.

Well-typed programs always play their roles: through compilation and
cryptography, there is always a way of detecting when things go
wrong. If I am a node in the system, and I get a message from a remote
node, then I have some notion of what I can trust from that remote
node. It might be that the remote node is being totally bogus, but that
can be detected.

The language is an extension of F\#, a Microsoft-developed variant of
ML. The output of the compiler is either concrete code full of
cryptography, of a symbolic model of the code.

Session types are basically a state machine. The language basically
encodes a finite state machine in the \pic.

It is possible to write a protocol that is inherently vulnerable. The
language makes it possible to detect these and get rid of them. For
example, if you have an offer and and a reject symbol going to two
different places, a compromised node might send both, and confuse the
global state. The paper gives a mechanical transformation from unsafe
sessions to more chatty but safe sessions. It also has a pretty good
notion of what information you have to maintain to keep the system
integrity. You only need to keep a log of the last few entries, known
as \emph{visibility} in the paper: this is much more compact than
maintaining the entire thing.

\begin{theorem} No attacker can compromise the system such that it
violates the protocol integrity.
\end{theorem}

Next time we will see the join calculus.


\end{document}</pre></body></html>