<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.sonho.fr//feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.sonho.fr//" rel="alternate" type="text/html" /><updated>2026-03-18T04:38:20+00:00</updated><id>https://www.sonho.fr//feed.xml</id><title type="html">Son HO</title><subtitle>Azure Research, Cambridge UK</subtitle><entry><title type="html">An Overview of the Aeneas Rust Verification Toolchain</title><link href="https://www.sonho.fr//2026/03/18/aeneas-overview.html" rel="alternate" type="text/html" title="An Overview of the Aeneas Rust Verification Toolchain" /><published>2026-03-18T00:00:00+00:00</published><updated>2026-03-18T00:00:00+00:00</updated><id>https://www.sonho.fr//2026/03/18/aeneas-overview</id><content type="html" xml:base="https://www.sonho.fr//2026/03/18/aeneas-overview.html"><![CDATA[<h1 id="an-overview-of-the-aeneas-rust-verification-toolchain">An Overview of the Aeneas Rust Verification Toolchain</h1>

<p>I finally took some time to write a blog-post that presents Aeneas.
This post is essentially the original ICFP 22 paper but with more examples
and up-to-date explanations (the formalism has evolved quite a bit).
The explanations I present here do not cover the latest features supported
by the implementation such as nested (mutable) borrows, iterators, or dyn traits,
but is nonetheless a quite comprehensive overview. Enjoy!</p>

<h2 id="introduction">Introduction</h2>

<p><a href="https://github.com/AeneasVerif/aeneas">Aeneas</a> is a verification toolchain
for Rust programs. It leverages Rust’s ownership discipline to translate Rust
code into pure functional programs, eliminating memory reasoning entirely. The
proof engineer can then verify the resulting code in a theorem prover such as
Lean, focusing on <em>functional</em> properties rather than on memory or aliasing.</p>

<p>The key observation is that a large class of safe Rust programs are functional in
essence. References and borrows are an implementation device for performance and memory
layout; coupled with Rust’s linear ownership discipline, these programs admit a pure
functional equivalent. Aeneas makes this equivalence concrete.
The key technical device that allows supporting the most subtle patterns,
functions returning mutable borrows, is something I called <em>backward functions</em>.</p>

<p>Aeneas is also more than a compiler from Rust to whatever theorem prover you want:
making the translation work required introducing novel semantics for safe Rust, while
the translation itself is performed by means of a symbolic execution (or abstract
interpretation, depending on your way of seeing things) for this semantics.
Importantly, this symbolic execution implements a borrow-checker, a fact that
we have formalized. This means that whenever you run Aeneas to translate a program
you actually also borrow-check it. Interestingly, this borrow-checker can validate
some programs that are not supported by the current borrow-checker or Polonius
(see the examples in the blog post).</p>

<p>Aeneas is being used in practice! Microsoft is
using it to verify implementations of the
<a href="https://github.com/microsoft/SymCrypt">SymCrypt</a> cryptographic library
(<a href="https://www.microsoft.com/en-us/research/blog/rewriting-symcrypt-in-rust-to-modernize-microsofts-cryptographic-library/">blog post</a>).</p>

<h2 id="aeneas-and-its-functional-translation-by-example">Aeneas and its Functional Translation, by Example</h2>

<p>Before jumping into the various facets of our formalism, we keep an eye on the
prize, and immediately showcase how Aeneas translates Rust programs to pure
equivalents. In this section, and for the remainder of this post, we use
Lean syntax for our functional translation; it greatly resembles OCaml and
other ML languages, and as such should be familiar to the reader. A brief note
about terminology: we refer to <em>regions</em>, emphasizing that a region encompasses a set of
borrows and loans at a given program point. The Rust compiler and documentation, however,
refer to <em>lifetimes</em>, which conveys the idea of a syntactic bracket, and a specific
implementation technique to enforce soundness. In this post, whenever we talk about Rust
specifically, we use “lifetime”; whenever we emphasize our semantic view of ownership, we
use “region”.</p>

<h3 id="mutable-borrows-functionally">Mutable Borrows, Functionally</h3>

<p>To warm up, we consider an example that, albeit small, showcases
many of Rust’s
features, including its ownership mechanism. In the Rust program below,
<code class="language-plaintext highlighter-rouge">incr</code> increments a reference, and <code class="language-plaintext highlighter-rouge">test_incr</code> acts as a
representative caller of the function.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">incr</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="nb">i32</span><span class="p">)</span> <span class="p">{</span>
  <span class="o">*</span><span class="n">x</span> <span class="o">=</span> <span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">test_incr</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">let</span> <span class="k">mut</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0i32</span><span class="p">;</span>
  <span class="nf">incr</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">y</span><span class="p">);</span>
  <span class="nd">assert!</span><span class="p">(</span><span class="n">y</span> <span class="o">==</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">incr</code> function operates by reference; that is, it receives the address of
a 32-bit signed integer <code class="language-plaintext highlighter-rouge">x</code>, as indicated by the <code class="language-plaintext highlighter-rouge">&amp;</code> (reference) type. In
addition, <code class="language-plaintext highlighter-rouge">incr</code> is allowed to modify the contents at address <code class="language-plaintext highlighter-rouge">x</code>, because
the reference is of the <code class="language-plaintext highlighter-rouge">mut</code> (mutable) kind, which permits memory
modification. Finally, the Rust type system enforces that mutable references
have a unique owner: the definition of <code class="language-plaintext highlighter-rouge">incr</code> type-checks, meaning that
the function not only <em>guarantees</em> it does not duplicate ownership of
<code class="language-plaintext highlighter-rouge">x</code>, but also can <em>rely</em> on the fact that no one else owns <code class="language-plaintext highlighter-rouge">x</code>.</p>

<p>In <code class="language-plaintext highlighter-rouge">test_incr</code>, we allocate a mutable value (<code class="language-plaintext highlighter-rouge">let mut</code>) on the stack; upon
calling <code class="language-plaintext highlighter-rouge">incr</code>, we take a mutable reference (<code class="language-plaintext highlighter-rouge">&amp;mut</code>) to <code class="language-plaintext highlighter-rouge">y</code>.
Statically, <code class="language-plaintext highlighter-rouge">y</code> becomes unavailable as long as <code class="language-plaintext highlighter-rouge">&amp;mut y</code> is active. In Rust
parlance, <code class="language-plaintext highlighter-rouge">y</code> is <em>mutably borrowed</em> and its ownership has been
transferred to the mutable reference.
To type-check the call, the type-checker performs a lifetime analysis: the
<code class="language-plaintext highlighter-rouge">incr</code> function has type <code class="language-plaintext highlighter-rouge">(&amp;'a mut i32) -&gt; ()</code>, and the <code class="language-plaintext highlighter-rouge">&amp;mut y</code>
borrow has type <code class="language-plaintext highlighter-rouge">&amp;'b mut i32</code>; both <code class="language-plaintext highlighter-rouge">'a</code> and <code class="language-plaintext highlighter-rouge">'b</code> are lifetime variables.</p>

<p>For now, suffices to say that the type-checker ascertains that the lifetime
<code class="language-plaintext highlighter-rouge">'b</code> of the mutable borrow satisfies the lifetime annotation <code class="language-plaintext highlighter-rouge">'a</code> in the
type of the callee, and deems the call valid.
Immediately after the call, Rust <em>terminates</em> the
region <code class="language-plaintext highlighter-rouge">'b</code>, in effect <em>relinquishing</em> ownership of the mutable reference
<code class="language-plaintext highlighter-rouge">&amp;'b mut y</code> so as to make <code class="language-plaintext highlighter-rouge">y</code> usable again inside <code class="language-plaintext highlighter-rouge">test_incr</code>.
This in turn allows the
<code class="language-plaintext highlighter-rouge">assert</code> to type-check, and thus the whole program.
Undoubtedly, this is a very minimalistic program; yet, there are two properties
of interest that we may want to establish already. The obvious one: the
assertion always succeeds. More subtly, doing so requires us to prove an
additional property, namely that the addition at line 2 does not overflow.</p>

<p>The key insight of Aeneas is that even though the program manipulates
references and borrows, none of this is informative when it comes to reasoning
about the program. More precisely: <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> are uniquely owned, meaning
that there are no stray aliases through which <code class="language-plaintext highlighter-rouge">x</code> or <code class="language-plaintext highlighter-rouge">y</code> may be modified;
in other words, to understand what happens to <code class="language-plaintext highlighter-rouge">y</code>, it suffices to track what
happens to <code class="language-plaintext highlighter-rouge">&amp;mut y</code>, and therefore to <code class="language-plaintext highlighter-rouge">x</code>.
Feeding this program to Aeneas generates the following translation, where
<code class="language-plaintext highlighter-rouge">+</code> is syntactic sugar for an Aeneas primitive that captures the semantics of
error-on-overflow in Rust.</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">incr</span> (<span class="n">x</span> : <span class="n">I32</span>) : <span class="n">Result</span> <span class="n">I32</span> :=
  <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="n">#i32</span><span class="cd"> -- evaluates to `fail` in case of overflow</span>

<span class="k">def</span> <span class="n">test_incr</span> : <span class="n">Result</span> <span class="n">Unit</span> := <span class="n">do</span>
  <span class="n">let</span> <span class="n">y</span> <span class="o">&lt;-</span> <span class="n">incr</span> <span class="mi">0</span><span class="n">#i32</span><span class="cd"> -- monadic bind</span>
  <span class="n">massert</span> (<span class="n">y</span> <span class="o">=</span> <span class="mi">1</span><span class="n">#i32</span>) <span class="cd">-- monadic assert</span>

<span class="n">#assert</span> (<span class="n">test_incr</span> <span class="o">=</span> <span class="n">ok</span> ())
</code></pre></div></div>

<p>This program is semantically equivalent to the original Rust code, but does not
rely on the memory: we have leveraged the precise ownership discipline of Rust
to generate a functional, pure version of the program. In hindsight, the usage
of references in Rust was merely an implementation detail, which is why
<code class="language-plaintext highlighter-rouge">incr</code> becomes a simple (possibly-overflowing) addition. Should the
call to <code class="language-plaintext highlighter-rouge">incr</code> succeed, its result is bound to <code class="language-plaintext highlighter-rouge">y</code>;
the <code class="language-plaintext highlighter-rouge">assert</code> simply becomes a boolean test that may generate a failure
in the error monad.</p>

<p>For the purposes of unit-testing, we can use Lean’s normalize to evaluate that
<code class="language-plaintext highlighter-rouge">test_incr</code> always succeeds, leveraging the fact that Aeneas produces an
executable translation, not a logical encoding.
In the remainder of this section, we use <code class="language-plaintext highlighter-rouge">&lt;-</code>, Lean’s bind
operator in the error monad.</p>

<h3 id="returning-a-mutable-borrow-and-backward-functions">Returning a Mutable Borrow, and Backward Functions</h3>

<p>Rust programs, however, rarely admit such immediate translations. To see why,
consider the following example, where the <code class="language-plaintext highlighter-rouge">choose</code> function returns a borrow,
as indicated by its return type <code class="language-plaintext highlighter-rouge">&amp;'a mut</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">choose</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">b</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span> <span class="p">{</span>
  <span class="k">if</span> <span class="n">b</span> <span class="p">{</span> <span class="k">return</span> <span class="n">x</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="n">y</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">test_choose</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0i32</span><span class="p">;</span>
  <span class="k">let</span> <span class="k">mut</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0i32</span><span class="p">;</span>
  <span class="k">let</span> <span class="n">z</span> <span class="o">=</span> <span class="nf">choose</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">y</span><span class="p">);</span>
  <span class="o">*</span><span class="n">z</span> <span class="o">=</span> <span class="o">*</span><span class="n">z</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">z</span> <span class="o">==</span> <span class="mi">1</span><span class="p">);</span>
  <span class="nd">assert!</span><span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="mi">1</span><span class="p">);</span>
  <span class="nd">assert!</span><span class="p">(</span><span class="n">y</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">choose</code> function is polymorphic over type <code class="language-plaintext highlighter-rouge">T</code> and lifetime <code class="language-plaintext highlighter-rouge">'a</code>; the
lifetime annotation captures the expectation that both <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> be in the
same region.
At call site, <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> are borrowed (line 7): they become unusable,
and give birth to two intermediary values <code class="language-plaintext highlighter-rouge">&amp;mut x</code> and <code class="language-plaintext highlighter-rouge">&amp;mut y</code> of type
<code class="language-plaintext highlighter-rouge">&amp;'a mut i32</code>. The value returned by <code class="language-plaintext highlighter-rouge">choose</code> also lives in region
<code class="language-plaintext highlighter-rouge">'a</code>, i.e., <code class="language-plaintext highlighter-rouge">z</code> also has type <code class="language-plaintext highlighter-rouge">&amp;'a mut i32</code>.
The usage of <code class="language-plaintext highlighter-rouge">z</code> (lines 8-9) is valid because the region <code class="language-plaintext highlighter-rouge">'a</code> still
exists; the Rust type-checker infers that region <code class="language-plaintext highlighter-rouge">'a</code> ought to be terminated
after line 9, which ends the borrows and therefore allows the caller to regain
full ownership of <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>, so that the <code class="language-plaintext highlighter-rouge">assert</code>s at lines 10-11 are
well-formed.</p>

<p>At first glance, it appears we can translate <code class="language-plaintext highlighter-rouge">choose</code> to an obvious
conditional.
But if we reason about the semantics of <code class="language-plaintext highlighter-rouge">choose</code> from the
caller’s perspective, it turns out that the intuitive translation is not
sufficient to capture what happens, e.g., the fact that <code class="language-plaintext highlighter-rouge">x</code> is updated while
<code class="language-plaintext highlighter-rouge">y</code> is left unchanged, as we observe at lines 10 and 11.
To solve this issue we observe that at call site, <code class="language-plaintext highlighter-rouge">choose</code> is an opaque,
separate function, meaning the caller
cannot reason about its precise definition — all that is
available is the function type. This type, however, contains precise region
information, which one can use to summarize its behavior.
When performing the function call, the ownership of <code class="language-plaintext highlighter-rouge">x</code> and
<code class="language-plaintext highlighter-rouge">y</code> is transferred to region <code class="language-plaintext highlighter-rouge">'a</code> in exchange for <code class="language-plaintext highlighter-rouge">z</code>; symmetrically,
when the lifetime
<code class="language-plaintext highlighter-rouge">'a</code> terminates, <code class="language-plaintext highlighter-rouge">z</code> is relinquished to region
<code class="language-plaintext highlighter-rouge">'a</code> in exchange for regaining ownership of <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>. The former
operation flows <em>forward</em>; the latter flows <em>backward</em>. Using a
separation-logic oriented analogy: borrows and regions encode a magic wand that
is introduced in a function call and eliminated when the corresponding region
terminates.</p>

<p>Our point is: both function call and region termination are semantically
meaningful. With the <code class="language-plaintext highlighter-rouge">choose</code> example,
Aeneas emits a <em>forward</em> function which itself returns a <em>backward</em> continuation.
The forward function is used to model the function call at line 7,
while the backward continuation is used to propagate changes back into <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>
when lifetime <code class="language-plaintext highlighter-rouge">'a</code> terminates.</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">choose</span> <span class="err">{</span><span class="n">T</span> : <span class="kt">Type</span><span class="err">}</span> (<span class="n">b</span> : <span class="n">Bool</span>) (<span class="n">x</span> : <span class="n">T</span>) (<span class="n">y</span> : <span class="n">T</span>) :
  <span class="n">Result</span> (<span class="n">T</span> <span class="o">×</span> (<span class="n">T</span> <span class="o">→</span> <span class="n">T</span> <span class="o">×</span> <span class="n">T</span>)) :=
  <span class="n">if</span> <span class="n">b</span>
  <span class="n">then</span> <span class="n">ok</span> (<span class="n">x</span>, <span class="k">fun</span> <span class="n">z</span> <span class="o">=&gt;</span> (<span class="n">z</span>, <span class="n">y</span>))
  <span class="n">else</span> <span class="n">ok</span> (<span class="n">y</span>, <span class="k">fun</span> <span class="n">z</span> <span class="o">=&gt;</span> (<span class="n">x</span>, <span class="n">z</span>))

<span class="k">def</span> <span class="n">test_choose</span> : <span class="n">Result</span> <span class="n">Unit</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">z</span>, <span class="n">choose_back</span>) <span class="o">&lt;-</span> <span class="n">choose</span> <span class="n">true</span> <span class="mi">0</span><span class="n">#i32</span> <span class="mi">0</span><span class="n">#i32</span>
  <span class="n">let</span> <span class="n">z1</span> <span class="o">&lt;-</span> <span class="n">z</span> <span class="o">+</span> <span class="mi">1</span><span class="n">#i32</span>
  <span class="n">massert</span> (<span class="n">z1</span> <span class="o">=</span> <span class="mi">1</span><span class="n">#i32</span>) <span class="cd">-- monadic assert</span>
  <span class="n">let</span> (<span class="n">x</span>, <span class="n">y</span>) := <span class="n">choose_back</span> <span class="n">z1</span>
  <span class="n">massert</span> (<span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="n">#i32</span>)
  <span class="n">massert</span> (<span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="n">#i32</span>)
  <span class="n">ok</span> ()

<span class="n">#assert</span> (<span class="n">test_choose</span> <span class="o">=</span> <span class="n">ok</span> ())
</code></pre></div></div>

<p>The call to <code class="language-plaintext highlighter-rouge">choose</code> returns a pair: the selected value, and a backward
continuation <code class="language-plaintext highlighter-rouge">choose_back</code>. We bind the result of the addition
(provided no overflow occurs) to <code class="language-plaintext highlighter-rouge">z1</code>; then, per the rules of Rust’s type-checker,
region <code class="language-plaintext highlighter-rouge">'a</code> terminates which compels us to call the backward continuation
<code class="language-plaintext highlighter-rouge">choose_back</code>.
The intuitive effect of calling <code class="language-plaintext highlighter-rouge">choose_back</code> is as follows: we relinquish
<code class="language-plaintext highlighter-rouge">z1</code>, which was in region <code class="language-plaintext highlighter-rouge">'a</code>; doing so, we propagate any updates
that may have been performed through <code class="language-plaintext highlighter-rouge">z</code> onto the
variables whose ownership was
transferred to <code class="language-plaintext highlighter-rouge">'a</code> in the first place, namely <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>.
This bidirectional approach is akin to lenses, except we propagate
the output back to possibly-many inputs; in this case, <code class="language-plaintext highlighter-rouge">z</code> is a view
over either <code class="language-plaintext highlighter-rouge">x</code> or <code class="language-plaintext highlighter-rouge">y</code>, and the backward function reflects the update to
<code class="language-plaintext highlighter-rouge">z</code> onto the original variables.
Thus, both variables are re-bound,
before chaining the two asserts.</p>

<p>The key advantage of returning the backward function as a continuation is that
it captures the choice made by <code class="language-plaintext highlighter-rouge">choose</code> (i.e., whether <code class="language-plaintext highlighter-rouge">b</code> was true or false)
in a closure, so the caller does not need to pass back the original arguments.</p>

<p>From the caller’s perspective, the computational content of <code class="language-plaintext highlighter-rouge">choose</code> is
unknown; but the signature of <code class="language-plaintext highlighter-rouge">choose</code> reveals the effect it may have onto its
inputs <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>, which in turns allows us to derive the type of the
forward and backward functions from the signature of <code class="language-plaintext highlighter-rouge">choose</code> itself.
The result is a modular, functional
translation that does not rely on any sort of cross-function inlining or
whole-program analysis.
To synthesize the backward continuation, it suffices to invert the direction
of assignments; in one case, <code class="language-plaintext highlighter-rouge">z</code> flows to <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> remains
unchanged; the other case is symmetrical.</p>

<h3 id="recursion-and-data-structures">Recursion and Data Structures</h3>

<p>It might not be immediately obvious that this translation technique scales up
beyond toy examples; we now crank up the complexity and
show how Aeneas can handle a wide variety of idioms while still delivering on the
original promise of a lightweight functional translation.
Our next example is
<code class="language-plaintext highlighter-rouge">list_nth_mut</code>, which allows taking a mutable reference to the <em>n</em>-th
element of a list, mutating it, and regaining ownership of the list.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">enum</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="nf">Cons</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="n">List</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&gt;</span><span class="p">),</span>
  <span class="nb">Nil</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">list_nth_mut</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span> <span class="p">{</span>
  <span class="k">match</span> <span class="n">l</span> <span class="p">{</span>
    <span class="nb">Nil</span> <span class="k">=&gt;</span> <span class="p">{</span> <span class="nd">panic!</span><span class="p">()</span> <span class="p">}</span>
    <span class="nf">Cons</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">tl</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
      <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span> <span class="n">x</span> <span class="p">}</span>
      <span class="k">else</span> <span class="p">{</span> <span class="nf">list_nth_mut</span><span class="p">(</span><span class="n">tl</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">sum</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="o">&amp;</span> <span class="n">List</span><span class="o">&lt;</span><span class="nb">i32</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">i32</span> <span class="p">{</span>
  <span class="k">match</span> <span class="n">l</span> <span class="p">{</span>
    <span class="nb">Nil</span> <span class="k">=&gt;</span> <span class="p">{</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span>
    <span class="nf">Cons</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">tl</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span> <span class="k">return</span> <span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="nf">sum</span><span class="p">(</span><span class="n">tl</span><span class="p">);</span> <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">test_nth</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">let</span> <span class="k">mut</span> <span class="n">l</span> <span class="o">=</span> <span class="nf">Cons</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nn">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nf">Cons</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nn">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nb">Nil</span><span class="p">))));</span>
  <span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="nf">list_nth_mut</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">l</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
  <span class="o">*</span><span class="n">x</span> <span class="o">=</span> <span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="nd">assert!</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="o">&amp;</span><span class="n">l</span><span class="p">)</span> <span class="o">==</span> <span class="mi">4</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This example relies on several new concepts. Parametric data type declarations
resemble those in any functional programming language such as OCaml
or SML. The <code class="language-plaintext highlighter-rouge">Box</code> type denotes a heap-allocated, uniquely-owned piece of
data. Without the <code class="language-plaintext highlighter-rouge">Box</code> indirection, <code class="language-plaintext highlighter-rouge">List</code> would describe a type of
infinite size and would be rejected. Immutable (or shared) borrows
do not sport a
<code class="language-plaintext highlighter-rouge">mut</code> keyword; they do not permit mutation, but the programmer may create
infinitely many of them. Only when all shared borrows have been relinquished
does full ownership return to the borrowed value.</p>

<p>The complete translation is as follows:</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">inductive</span> <span class="n">List</span> (<span class="n">T</span> : <span class="kt">Type</span>) :=
<span class="o">|</span> <span class="n">Cons</span> : <span class="n">T</span> <span class="o">-&gt;</span> <span class="n">List</span> <span class="n">T</span> <span class="o">-&gt;</span> <span class="n">List</span> <span class="n">T</span>
<span class="o">|</span> <span class="n">Nil</span> : <span class="n">List</span> <span class="n">T</span>

<span class="k">def</span> <span class="n">list_nth_mut</span> <span class="err">{</span><span class="n">T</span> : <span class="kt">Type</span><span class="err">}</span> (<span class="n">l</span> : <span class="n">List</span> <span class="n">T</span>) (<span class="n">i</span> : <span class="n">Usize</span>) :
  <span class="n">Result</span> (<span class="n">T</span> <span class="o">×</span> (<span class="n">T</span> <span class="o">-&gt;</span> <span class="n">List</span> <span class="n">T</span>)) :=
  <span class="k">match</span> <span class="n">l</span> <span class="k">with</span>
  <span class="o">|</span> <span class="n">Cons</span> <span class="n">x</span> <span class="n">tl</span> <span class="o">=&gt;</span>
    <span class="n">if</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="n">#usize</span>
    <span class="n">then</span> <span class="n">ok</span> (<span class="n">x</span>, <span class="k">fun</span> <span class="n">x</span><span class="err">'</span> <span class="o">=&gt;</span> <span class="n">Cons</span> <span class="n">x</span><span class="err">'</span> <span class="n">tl</span>)
    <span class="n">else</span> <span class="n">do</span>
      <span class="n">let</span> <span class="n">i1</span> <span class="o">&lt;-</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="n">#usize</span>
      <span class="n">let</span> (<span class="n">v</span>, <span class="n">list_nth_mut_back</span>) <span class="o">&lt;-</span> <span class="n">list_nth_mut</span> <span class="n">tl</span> <span class="n">i1</span>
      <span class="n">ok</span> (<span class="n">v</span>, <span class="k">fun</span> <span class="n">v</span><span class="err">'</span> <span class="o">=&gt;</span> <span class="n">Cons</span> <span class="n">x</span> (<span class="n">list_nth_mut_back</span> <span class="n">v</span><span class="err">'</span>))
  <span class="o">|</span> <span class="n">Nil</span> <span class="o">=&gt;</span> <span class="n">fail</span>

<span class="k">def</span> <span class="n">sum</span> (<span class="n">l</span> : <span class="n">List</span> <span class="n">I32</span>) : <span class="n">Result</span> <span class="n">I32</span> :=
  <span class="k">match</span> <span class="n">l</span> <span class="k">with</span>
  <span class="o">|</span> <span class="n">Cons</span> <span class="n">x</span> <span class="n">tl</span> <span class="o">=&gt;</span> <span class="n">do</span>
    <span class="n">let</span> <span class="n">i</span> <span class="o">&lt;-</span> <span class="n">sum</span> <span class="n">tl</span>
    <span class="n">x</span> <span class="o">+</span> <span class="n">i</span>
  <span class="o">|</span> <span class="n">Nil</span> <span class="o">=&gt;</span> <span class="n">ok</span> <span class="mi">0</span><span class="n">#i32</span>

<span class="k">def</span> <span class="n">test_nth</span> : <span class="n">Result</span> <span class="n">Unit</span> := <span class="n">do</span>
  <span class="n">let</span> <span class="n">l</span> := <span class="n">Cons</span> <span class="mi">1</span> (<span class="n">Cons</span> <span class="mi">2</span> <span class="n">Nil</span>)
  <span class="n">let</span> (<span class="n">x</span>, <span class="n">list_nth_mut_back</span>) <span class="o">&lt;-</span> <span class="n">list_nth_mut</span> <span class="n">l</span> <span class="mi">1</span>
  <span class="n">let</span> <span class="n">x1</span> <span class="o">&lt;-</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span><span class="n">#i32</span>
  <span class="n">let</span> <span class="n">l1</span> := <span class="n">list_nth_mut_back</span> <span class="n">x1</span>
  <span class="n">let</span> <span class="n">i</span> <span class="o">&lt;-</span> <span class="n">sum</span> <span class="n">l1</span>
  <span class="n">massert</span> (<span class="n">i</span> <span class="o">=</span> <span class="mi">4</span><span class="n">#i32</span>)

<span class="n">#assert</span> (<span class="n">test_nth</span> <span class="o">=</span> <span class="n">ok</span> ())
</code></pre></div></div>

<p>We first focus on the caller’s point of view.
Continuing with the lens analogy, we focus on (or “get”) the <em>n</em>-th element of the list via
a call to <code class="language-plaintext highlighter-rouge">list_nth_mut</code>; modify the element; then
close (or “put” back) the lens, and propagate the modification back to the
list via a call to <code class="language-plaintext highlighter-rouge">list_nth_mut_back</code>.
The backward continuation is of particular interest.
In the <code class="language-plaintext highlighter-rouge">Nil</code> case (i.e., when <code class="language-plaintext highlighter-rouge">i = 0</code>), it simply updates the list to replace the head (<code class="language-plaintext highlighter-rouge">x</code>) with its
new value (<code class="language-plaintext highlighter-rouge">x'</code>).
In the <code class="language-plaintext highlighter-rouge">Cons</code> case, it updates the tail of the list by using the backward continuation
returned by the recursive call,
and reconstructs the complete list by consing the (unchanged) head value.</p>

<h2 id="an-ownership-centric-semantics-for-rust">An Ownership-Centric Semantics for Rust</h2>

<p>Before explaining the functional translation above,
we must first present our
input language and its operational semantics. We now present a series of short
Rust snippets, and show in comments how our execution environments model the
effect of each statement.
The language we use is called LLBC (Low Level Borrow Calculus). It is essentially MIR
but with a reconstructed control-flow and a bit of cleaning. In effect, it looks like
Rust’s surface syntax, but where everything is explicit, in particular moves and copies.</p>

<h4 id="mutable-borrows">Mutable borrows</h4>

<p>After line 1, <code class="language-plaintext highlighter-rouge">x</code> points to <code class="language-plaintext highlighter-rouge">0</code>, which we write <code class="language-plaintext highlighter-rouge">x ↦ 0</code>. At line 2, <code class="language-plaintext highlighter-rouge">px</code> <em>mutably</em> borrows <code class="language-plaintext highlighter-rouge">x</code> (“MB” stands for “mutable borrow”). As we
mentioned earlier, a mutable borrow grants exclusive ownership of a value, and
renders the borrowed value unusable for the duration of the borrow. We reflect this
fact in our execution environment as follows: <code class="language-plaintext highlighter-rouge">x</code> is marked as
“loaned-out” (“ML” stands for “mutable loan”), in a mutable fashion, and <code class="language-plaintext highlighter-rouge">px</code> is known to be a
mutable borrow. Furthermore, ownership of the borrowed value now
rests with <code class="language-plaintext highlighter-rouge">px</code>, so the value within the mutable borrow is 0. Finally, we
need to record that <code class="language-plaintext highlighter-rouge">px</code> is a borrow <em>of <code class="language-plaintext highlighter-rouge">x</code></em>: we issue a fresh loan
identifier ℓ that ties <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">px</code> together.
The same operation is repeated at line 3. Value 0 is now held by <code class="language-plaintext highlighter-rouge">ppx</code>, and
<code class="language-plaintext highlighter-rouge">px</code>, too, becomes “loaned out”.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>       <span class="c1">// x ↦ 0</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">px</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// x ↦ ML ℓ,   px ↦ MB ℓ 0</span>
<span class="k">let</span> <span class="n">ppx</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">px</span><span class="p">;</span>   <span class="c1">// x ↦ ML ℓ,   px ↦ ML ℓ',     ppx ↦ MB ℓ' (MB ℓ 0)</span>
</code></pre></div></div>

<p>Our environments thus precisely track ownership; doing so, they capture the aliasing
graph in an exact fashion. Another point about our style:
this representation allows us to adopt a <em>focused</em> view of the borrowed
value (e.g., 0), solely
through its owner (e.g., <code class="language-plaintext highlighter-rouge">ppx</code>), without worrying about following indirections
to other variables.
We believe this
approach is unique to our semantics; it has, in our experience, greatly
simplified our reasoning and in particular the functional translation.</p>

<p>We remark that our style
departs from Stacked Borrows, where the modified value
remains with <code class="language-plaintext highlighter-rouge">x</code>. We also note that our formalism cannot account for unsafe
blocks; allowing unfettered aliasing would lead to potential cycles, which we
cannot represent. This is an intentional design choice for us: we circumbscribe
the problem space in order to achieve an intuitive, natural semantics and a
lightweight functional translation. Aeneas shines on non-unsafe Rust programs,
and can be complemented by more advanced tools such as RustBelt for unsafe
parts.</p>

<h4 id="shared-borrows">Shared borrows</h4>

<p>Shared borrows behave more like traditional pointers. Multiple shared borrows
may be created for the same value; each of them grants read-only access to the
underlying value.
The owner also retains a read-only access to the borrowed value;
regaining full ownership requires
terminating all of the borrows. In the example
below, the value (0, 1) is borrowed in a shared fashion, at line 2. This time,
the value remains with <code class="language-plaintext highlighter-rouge">x</code>; but taking an immutable reference to
<code class="language-plaintext highlighter-rouge">x</code> still requires book-keeping. We issue a new loan ℓ, and record that
<code class="language-plaintext highlighter-rouge">px1</code> is now a shared borrow associated to loan ℓ; to understand which
value <code class="language-plaintext highlighter-rouge">px1</code> points to, we simply look up in the environment who is the owner
of ℓ, and read the associated value.
Repeated shared borrows are permitted: at line 3,
we create a new shared borrow of <code class="language-plaintext highlighter-rouge">x</code>; as <code class="language-plaintext highlighter-rouge">x</code> is already borrowed we do not need to
update its value and simply reuse the loan identifier ℓ.
At line 4, we copy the first component of <code class="language-plaintext highlighter-rouge">x</code>; remember that moves and copies are explicit
in our language. Values that are loaned
immutably, like <code class="language-plaintext highlighter-rouge">x</code>, can still be read; in the resulting environment, <code class="language-plaintext highlighter-rouge">y</code> points to a copy of
the first component, and bears no relationship whatsoever to <code class="language-plaintext highlighter-rouge">x</code>.
Finally, at line 5, we <em>reborrow</em> (through <code class="language-plaintext highlighter-rouge">px1</code>) the first component of
the pair only. First, to dereference <code class="language-plaintext highlighter-rouge">px1</code>, we perform a lookup and find that
<code class="language-plaintext highlighter-rouge">x</code> owns ℓ. Then, we perform book-keeping and update the value loaned by
<code class="language-plaintext highlighter-rouge">x</code>, so as to reflect that its first component has been loaned out, introducing a fresh
loan identifier ℓ’ at the same time.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>    <span class="c1">// x ↦ (0, 1)</span>
<span class="k">let</span> <span class="n">px1</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>      <span class="c1">// x ↦ SL ℓ (0,1),       px1 ↦ SB ℓ</span>
<span class="k">let</span> <span class="n">px2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>      <span class="c1">// x ↦ SL ℓ (0, 1),      px1 ↦ SB ℓ,   px2 ↦ SB ℓ</span>
<span class="k">let</span> <span class="n">y</span> <span class="o">=</span> <span class="n">copy</span> <span class="n">x</span><span class="na">.0</span><span class="p">;</span>  <span class="c1">// x ↦ SL ℓ (0, 1),      px1 ↦ SB ℓ,   px2 ↦ SB ℓ,   y ↦ 0</span>
<span class="k">let</span> <span class="n">z</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">(</span><span class="o">*</span><span class="n">px1</span><span class="na">.0</span><span class="p">);</span> <span class="c1">// x ↦ SL ℓ ((SL ℓ' 0), 1), px1 ↦…, px2 ↦ …, y ↦ 0, z ↦ SB ℓ'</span>
</code></pre></div></div>

<p>Note that <code class="language-plaintext highlighter-rouge">px1</code> and <code class="language-plaintext highlighter-rouge">px2</code> share the <em>same</em> loan identifier ℓ: shared
borrow identifiers are not unique. This is in contrast with mutable borrows, where
each borrow has a unique loan identifier to enforce exclusive ownership.
For shared borrows, since no mutation is allowed, there is no need to distinguish
between different borrows of the same value — they all grant the same read-only
access. As a consequence, ending a shared loan simply requires checking that there
are no more live borrows referencing that loan.</p>

<p>In our presentation, shared borrows behave like pointers, and every one of them
is statically accounted for via the loan identifier attached to the borrowed value.
The reader might find this design choice surprising: indeed, in Rust, shared
borrows behave like immutable values and we ought to be able to treat them as
such. Recall, however, that one of our key design goals is to give a
<em>semantic</em> explanation of borrows; as such, our precise tracking of
shared borrows allows us to know precisely when all aliases
have been relinquished, and full ownership of the borrowed value has been
regained. This allows us to justify why, in the example below, the update to
<code class="language-plaintext highlighter-rouge">x</code> is sound; without our exact alias tracking, we would have to trust the
borrow checker, something we explicitly do not want to do.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>  <span class="c1">// x ↦ 0</span>
<span class="k">let</span> <span class="n">px1</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>   <span class="c1">// x ↦ SL ℓ 0,       px1 ↦ SB ℓ</span>
<span class="k">let</span> <span class="n">px2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>   <span class="c1">// x ↦ SL ℓ 0,       px1 ↦ SB ℓ,   px2 ↦ SB ℓ</span>
                <span class="c1">// After ending the loan ℓ:</span>
                <span class="c1">// x ↦ 0,   px1 ↦ ⊥,   px2 ↦ ⊥</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>          <span class="c1">// x ↦ 1</span>
</code></pre></div></div>

<p>Finally, we reiterate our remark that our formalism allows keeping track of the aliasing
graph in a precise fashion; the discipline of Rust bans cycles, meaning that the
aliasing graph is always a tree. This style of representation resembles
Mezzo, where loan identifiers are akin to singleton
types, and entries in the environment are akin to permissions.</p>

<h4 id="rewriting-an-old-value-aka-reborrowing">Rewriting an Old Value, a.k.a. Reborrowing</h4>

<p>We now consider a particularly twisted example accepted by the Rust compiler. While the
complexity seems at first gratuitous, it turns out that the pattern of borrowing
a dereference (i.e., <code class="language-plaintext highlighter-rouge">&amp;mut (*px)</code>) is particularly common in Rust. The reason
is subtle: in the post-desugaring MIR internal Rust representation, moves and
copies are explicit, meaning function calls of the form <code class="language-plaintext highlighter-rouge">f(move px)</code> abound.
Such function calls <em>consume</em> their argument, and render the
user-declared reference <code class="language-plaintext highlighter-rouge">px</code> unusable past the function call.
To offer a better user experience, Rust automatically “reborrows” the
contents pointed to by <code class="language-plaintext highlighter-rouge">px</code>, and rewrites the call into <code class="language-plaintext highlighter-rouge">f(move (&amp;mut (*px)))</code> at desugaring-time.
Thus, only the intermediary value is “lost” to the function call;
relying on its lifetime analysis, the Rust compiler concludes that the
user-declared reference <code class="language-plaintext highlighter-rouge">px</code> remains valid past the function call, hence
making the programmer’s life easier.</p>

<p>Another common pattern is to directly mutate a borrow, i.e., assign a fresh
borrow into a variable <code class="language-plaintext highlighter-rouge">x</code> of type <code class="language-plaintext highlighter-rouge">&amp;mut t</code> that was <em>itself</em>
declared as <code class="language-plaintext highlighter-rouge">let mut</code>.
Capturing the semantics of such an update must be done with great care, in order
to preserve precise aliasing information.</p>

<p>We propose an example that combines both patterns; the fact that we make
<code class="language-plaintext highlighter-rouge">px</code> reborrow itself is what makes the example “twisted”.
Rust accepts this
program; we now explain with our semantics <em>why</em> it is sound.
In the example below, after line
2, the environment offers no surprises. Justifying the write at line 3 requires
care. We borrow <code class="language-plaintext highlighter-rouge">*px</code>, which modifies <code class="language-plaintext highlighter-rouge">px</code> to point to <code class="language-plaintext highlighter-rouge">MB ℓ' 0</code>,
and returns <code class="language-plaintext highlighter-rouge">ML ℓ'</code>; the value about to be overwritten is stored in a
fresh variable <code class="language-plaintext highlighter-rouge">px_old</code>, and <code class="language-plaintext highlighter-rouge">ML ℓ'</code>
gets written to <code class="language-plaintext highlighter-rouge">px</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>       <span class="c1">// x ↦ 0</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">px</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// x ↦ ML ℓ,   px ↦ MB ℓ 0</span>
<span class="n">px</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">(</span><span class="o">*</span><span class="n">px</span><span class="p">);</span>     <span class="c1">// x ↦ ML ℓ,   px_old ↦ MB ℓ (ML ℓ'),   px ↦ MB ℓ' 0</span>
                     <span class="c1">// x ↦ ML ℓ,   px_old ↦ MB ℓ 0, px ↦⊥</span>
<span class="nd">assert!</span><span class="p">(</span><span class="n">x</span><span class="o">==</span><span class="mi">0</span><span class="p">);</span>       <span class="c1">// x ↦ 0, px_old ↦ ⊥, px ↦ ⊥</span>
</code></pre></div></div>

<p>Saving the old value is crucial for line 4.
For the assertion, we need to regain full ownership of <code class="language-plaintext highlighter-rouge">x</code>. To do so,
we first terminate ℓ’.
This <em>reorganizes</em> the environment, with two consequences.
First, <code class="language-plaintext highlighter-rouge">px</code> becomes unusable, which we write <code class="language-plaintext highlighter-rouge">px ↦ ⊥</code>. Second, <code class="language-plaintext highlighter-rouge">px_old</code>, which we had judiciously kept in the
environment, becomes <code class="language-plaintext highlighter-rouge">MB ℓ 0</code>. We reorganize the environment again, to
terminate ℓ; the effect is similar, and results in <code class="language-plaintext highlighter-rouge">x ↦ 0</code>, i.e., full ownership of <code class="language-plaintext highlighter-rouge">x</code>.
This example illustrates a key characteristic of our approach, which is that we
reorganize borrows in a lazy fashion, and don’t terminate a borrow until we
need to get the borrowed value back.</p>

<h4 id="an-illegal-borrow">An Illegal Borrow</h4>

<p>We offer an final example which leverages our reorganization rules;
furthermore, the example illustrates how our semantics reaches the same
conclusion as <code class="language-plaintext highlighter-rouge">rustc</code>, though by different means, on a borrowing error.
At line 2, a borrow is introduced, which results in a fresh loan ℓ.
To make progress, we
terminate borrow ℓ at line 3.
Line 4 then type-checks, with a fresh borrow ℓ’. Then, we error
out at line 5: <code class="language-plaintext highlighter-rouge">px₁</code> has been terminated, and we cannot dereference ⊥.</p>

<p>The Rust compiler proceeds differently, and implements an analysis which
requires computing borrow constraints for an entire function body.
The compiler notices that lifetime ℓ must go on until line 6 (because of
the assert), which prevents a new borrow from being issued at line 4. Rust
thus ascribes the error to an earlier location than we do, that is, line 4.
We remark that the Rust behavior is semantically equivalent to ours; however, our
lazy approach which terminates borrows only as needed has the advantage that
evaluation can proceed in a purely forward fashion, without requiring a
non-local analysis. This on-demand approach is similar to Stacked
Borrows.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>    <span class="c1">// x ↦ 0</span>
<span class="k">let</span> <span class="n">px1</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// x ↦ ML ℓ,   px1 ↦ MB ℓ 0</span>
                  <span class="c1">// x ↦ 0,   px1 ↦ ⊥</span>
<span class="k">let</span> <span class="n">px2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// aeneas: x ↦ ML ℓ',   px1 ↦ ⊥,    px2 ↦ MB ℓ' 0</span>
                  <span class="c1">// rustc: error: cannot borrow `px1` as mutable more than once at a time</span>
<span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">px1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// aeneas: error, attempt to deference unusable variable px1</span>
</code></pre></div></div>

<h4 id="two-phase-borrows">Two-Phase Borrows</h4>

<p>We finally review <em>two-phase</em> borrows, which are introduced by the Rust compiler
at desugaring time. A two-phase borrow starts as a shared borrow in a
“reservation phase”, and later gets activated into a full mutable borrow.
Reserved borrows enable a variety of very common idioms without resorting to
more advanced desugarings.</p>

<p>Below, we create a two-phase borrow at line 3. From the point of view of the
lender, a two-phase borrow acts as a shared borrow; the value of <code class="language-plaintext highlighter-rouge">x</code>, which
is already immutably borrowed, remains unchanged. However, <code class="language-plaintext highlighter-rouge">px2</code> maps to the
<em>reserved</em> borrow <code class="language-plaintext highlighter-rouge">RB ℓ</code>.
At line 4, we evaluate the assertion as before.
However, at line 5 we need to use the two-phase borrow to perform an in-place
update. We thus reorganize the environment by ending the shared borrow ℓ
contained by <code class="language-plaintext highlighter-rouge">px1</code>. There now only remains a single borrow pointing to <code class="language-plaintext highlighter-rouge">x</code>,
the reserved borrow of <code class="language-plaintext highlighter-rouge">px2</code>, that we can promote to a mutable borrow. This
allows us to evaluate the in-place update.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>          <span class="c1">// x ↦ 0</span>
<span class="k">let</span> <span class="n">px1</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;</span>           <span class="c1">// x ↦ SL ℓ 0,       px1 ↦ SB ℓ</span>
<span class="k">let</span> <span class="n">px2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">two</span><span class="o">-</span><span class="n">phase</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// x ↦ SL ℓ 0,       px1 ↦ SB ℓ,   px2 ↦ RB ℓ</span>
<span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">px1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>     <span class="c1">// x ↦ SL ℓ 0,       px1 ↦ SB ℓ,   px2 ↦ RB ℓ</span>
                        <span class="c1">// After ending the shared borrow of px1:</span>
                        <span class="c1">// x ↦ SL ℓ 0,       px1 ↦ ⊥,      px2 ↦ RB ℓ</span>
                        <span class="c1">// After promoting the reserved borrow of px2:</span>
                        <span class="c1">// x ↦ ML ℓ,         px1 ↦ ⊥,      px2 ↦ MB ℓ 0</span>
<span class="o">*</span><span class="n">px2</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>               <span class="c1">// x ↦ ML ℓ,         px1 ↦ ⊥,      px2 ↦ MB ℓ 1</span>
</code></pre></div></div>

<h2 id="from-symbolic-semantics-to-functional-code">From Symbolic Semantics to Functional Code</h2>

<p>We now explain how Aeneas, using the symbolic semantics, generates a pure translation
of the original LLBC program. We show this through two detailed examples:
first the translation of a <em>caller</em> (<code class="language-plaintext highlighter-rouge">call_choose</code>), then the translation
of a <em>callee</em> (<code class="language-plaintext highlighter-rouge">choose</code>) which requires synthesizing a backward function.</p>

<p>The translation is carried out by performing a symbolic execution on the source
program and synthesizing a functional AST in parallel. At each step, we show
the symbolic environment alongside the progressively-built Lean translation.</p>

<p>A key insight is that the synthesis rules are exclusively concerned with
<em>symbolic values</em>; the actual variables from the source program (<code class="language-plaintext highlighter-rouge">x ↦ ...</code>)
are mere bookkeeping devices and have no relevance to the translated program.
Symbolic values σ, however, cannot be determined statically; they thus compute
at run-time, and as such are let-bound in the target program.</p>

<h3 id="translation-example-call_choose">Translation Example: <code class="language-plaintext highlighter-rouge">call_choose</code></h3>

<p>As a starting example, we consider the translation of the <code class="language-plaintext highlighter-rouge">call_choose</code> function
below, presented in LLBC syntax with explicit writes and moves, along with a
fully-explicit return variable <code class="language-plaintext highlighter-rouge">x_ret</code>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">call_choose</span><span class="p">(</span><span class="k">mut</span> <span class="n">p</span> <span class="p">:</span> <span class="p">(</span><span class="nb">u32</span><span class="p">,</span> <span class="nb">u32</span><span class="p">))</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
  <span class="k">let</span> <span class="n">px</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">p</span><span class="na">.0</span><span class="p">;</span>                       <span class="c1">// line 2</span>
  <span class="k">let</span> <span class="n">py</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">p</span><span class="na">.1</span><span class="p">;</span>                       <span class="c1">// line 3</span>
  <span class="k">let</span> <span class="n">pz</span> <span class="o">=</span> <span class="nf">choose</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="k">move</span> <span class="n">px</span><span class="p">,</span> <span class="k">move</span> <span class="n">py</span><span class="p">);</span> <span class="c1">// line 4</span>
  <span class="o">*</span><span class="n">pz</span> <span class="o">=</span> <span class="o">*</span><span class="n">pz</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>                           <span class="c1">// line 5</span>
  <span class="n">x_ret</span> <span class="o">=</span> <span class="k">move</span> <span class="n">p</span><span class="na">.0</span><span class="p">;</span>                        <span class="c1">// line 6</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We start the translation by initializing an environment where <code class="language-plaintext highlighter-rouge">p</code> maps to a
symbolic value σ₀. In parallel, we synthesize the function as an AST with a
hole <code class="language-plaintext highlighter-rouge">[.]</code> to be progressively filled.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p ↦ (σ₀ : (u32, u32))
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">s0</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) :
  <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>At line 2, accessing field 0 requires us to expand σ₀; doing so introduces a
let-binding in the translation.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p ↦ (σ₁ : u32, σ₂ : u32)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">s0</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) :
  <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">s1</span>, <span class="n">s2</span>) := <span class="n">s0</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>The expansion allows us to evaluate the two mutable borrows on lines 2–3.
Importantly, borrows and assignments just lead to bookkeeping in the
environment: the synthesized translation is left unchanged.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p  ↦ (ML ℓ₁, ML ℓ₂)
px ↦ MB ℓ₁ (σ₁ : u32)
py ↦ MB ℓ₂ (σ₂ : u32)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">s0</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) :
  <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">s1</span>, <span class="n">s2</span>) := <span class="n">s0</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>We then reach the function call at line 4. To account for the call, we introduce
a region abstraction to account for <code class="language-plaintext highlighter-rouge">'a</code>, transfer ownership of the effective
arguments to the abstraction, then introduce a fresh mutably borrowed value
<code class="language-plaintext highlighter-rouge">MB ℓ₃ (σ₃ : u32)</code> to account for the returned value stored in <code class="language-plaintext highlighter-rouge">pz</code>.
We also attach a <em>continuation</em> to the region abstraction A(α) that we
will use upon ending A(α). This continuation is simply the backward function
of <code class="language-plaintext highlighter-rouge">choose</code>; it consumes the value retrieved upon ending ℓ₃ and produces
the values to give back to ℓ₁ and ℓ₂.</p>

<p>In parallel, we introduce a call to <code class="language-plaintext highlighter-rouge">choose</code> in the synthesized translation. The
borrow types are translated to the identity; the input arguments are thus simply
<code class="language-plaintext highlighter-rouge">s1</code> and <code class="language-plaintext highlighter-rouge">s2</code>, while <code class="language-plaintext highlighter-rouge">choose</code> outputs <code class="language-plaintext highlighter-rouge">s3</code>, together with the backward
function <code class="language-plaintext highlighter-rouge">back</code>.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p  ↦ (ML ℓ₁, ML ℓ₂)
px ↦ ⊥
py ↦ ⊥

A(α) {
    _,
    MB ℓ₁ (σ₁ : u32),
    MB ℓ₂ (σ₂ : u32),
    ML ℓ₃,
} ⟦ (ℓ₁, ℓ₂): λ ℓ₃ ⇒ back ℓ₃ ⟧

pz ↦ MB ℓ₃ (σ₃ : u32)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">s0</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) :
  <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">s1</span>, <span class="n">s2</span>) := <span class="n">s0</span>
  <span class="n">let</span> (<span class="n">s3</span>, <span class="n">back</span>) <span class="err">←</span> <span class="n">choose</span> <span class="n">true</span> <span class="n">s1</span> <span class="n">s2</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>We can now symbolically execute the increment, which merely introduces an
addition and generates a fresh variable σ₄:</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p  ↦ (ML ℓ₁, ML ℓ₂)
px ↦ ⊥
py ↦ ⊥

A(α) {
    _,
    MB ℓ₁ (σ₁ : u32),
    MB ℓ₂ (σ₂ : u32),
    ML ℓ₃,
} ⟦ (ℓ₁, ℓ₂): λ ℓ₃ ⇒ back ℓ₃ ⟧

pz ↦ MB ℓ₃ (σ₄ : u32)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">s0</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) :
  <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">s1</span>, <span class="n">s2</span>) := <span class="n">s0</span>
  <span class="n">let</span> (<span class="n">s3</span>, <span class="n">back</span>) <span class="err">←</span> <span class="n">choose</span> <span class="n">true</span> <span class="n">s1</span> <span class="n">s2</span>
  <span class="n">let</span> <span class="n">s4</span> <span class="err">←</span> <span class="n">s3</span> <span class="o">+</span> <span class="mi">1</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>Finally, the move at line 6 requires retrieving the ownership of <code class="language-plaintext highlighter-rouge">p.0</code>. Doing
so requires ending the region abstraction A(α) (introduced by the call to
<code class="language-plaintext highlighter-rouge">choose</code>), which in turn requires ending the loan inside the abstraction.
Accordingly, we first end ℓ₃ which leads to the environment below.
Importantly, we update the continuation associated with A(α) to account for
the fact that it consumes the value given back upon ending ℓ₃.
Ending a loan (or a borrow, depending on the point of view) leaves the
synthesized code unchanged.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p  ↦ (ML ℓ₁, ML ℓ₂)
px ↦ ⊥
py ↦ ⊥

A(α) {
    _,
    MB ℓ₁ (σ₁ : u32),
    MB ℓ₂ (σ₂ : u32),
    (σ₄ : u32)
} ⟦ (ℓ₁, ℓ₂): back σ₄ ⟧

pz ↦ ⊥
</code></pre></div></div>

<p>Then, we actually end the region abstraction A(α) by moving back the borrows
ℓ₁ and ℓ₂ in the environment, with fresh symbolic values σ₅ and σ₆. Those
are the values given back <em>by</em> <code class="language-plaintext highlighter-rouge">choose</code>. On the side of the translated code,
we materialize the end of A(α) by introducing a call to its continuation. This
continuation consumes the value given back to the loan ℓ₃ upon ending it (that
is, σ₄); it also outputs the values given back to ℓ₁ and ℓ₂ (that is, the
pair (σ₅, σ₆)).</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>p  ↦ (ML ℓ₁, ML ℓ₂)
px ↦ ⊥
py ↦ ⊥
_  ↦ MB ℓ₁ (σ₅ : u32)
_  ↦ MB ℓ₂ (σ₆ : u32)
pz ↦ ⊥
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">s0</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) :
  <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">s1</span>, <span class="n">s2</span>) := <span class="n">s0</span>
  <span class="n">let</span> (<span class="n">s3</span>, <span class="n">back</span>) <span class="err">←</span> <span class="n">choose</span> <span class="n">true</span> <span class="n">s1</span> <span class="n">s2</span>
  <span class="n">let</span> <span class="n">s4</span> <span class="err">←</span> <span class="n">s3</span> <span class="o">+</span> <span class="mi">1</span>
  <span class="n">let</span> (<span class="n">s5</span>, <span class="n">s6</span>) <span class="err">←</span> <span class="n">back</span> <span class="n">s4</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>We can finally end the borrow ℓ₁ and evaluate the <code class="language-plaintext highlighter-rouge">return</code>, which ends the
translation. As we save meta-information about the assignments to generate
suitable names for the variables, Aeneas actually generates the following
function:</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">call_choose</span> (<span class="n">p</span> : (<span class="n">U32</span> <span class="o">×</span> <span class="n">U32</span>)) : <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> (<span class="n">px</span>, <span class="n">py</span>) := <span class="n">p</span>
  <span class="n">let</span> (<span class="n">pz</span>, <span class="n">back</span>) <span class="err">←</span> <span class="n">choose</span> <span class="n">true</span> <span class="n">px</span> <span class="n">py</span>
  <span class="n">let</span> <span class="n">pz0</span> <span class="err">←</span> <span class="n">pz</span> <span class="o">+</span> <span class="mi">1</span>
  <span class="n">let</span> (<span class="n">px0</span>, <span class="n">_</span>) <span class="err">←</span> <span class="n">back</span> <span class="n">pz0</span>
  <span class="n">ok</span> <span class="n">px0</span>
</code></pre></div></div>

<h3 id="translation-example-choose">Translation Example: <code class="language-plaintext highlighter-rouge">choose</code></h3>

<p>We now proceed with the synthesis of <code class="language-plaintext highlighter-rouge">choose</code>, which requires synthesizing a
backward function. We recall its definition; like in the previous example,
we make all the statements explicit.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">choose</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">b</span> <span class="p">:</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">x</span> <span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span><span class="p">,</span> <span class="n">y</span> <span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">T</span> <span class="p">{</span>
  <span class="k">if</span> <span class="n">b</span> <span class="p">{</span>
    <span class="n">x_ret</span> <span class="o">=</span> <span class="k">move</span> <span class="n">x</span><span class="p">;</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">x_ret</span> <span class="o">=</span> <span class="k">move</span> <span class="n">y</span><span class="p">;</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Unlike <code class="language-plaintext highlighter-rouge">call_choose</code>, the <code class="language-plaintext highlighter-rouge">choose</code> function takes borrows as input parameters.
We thus need to track their provenance, from the point of view of the callee.
As a consequence, we initialize the environment by introducing an abstraction
containing loans so as to model the values owned by the caller and <em>loaned</em> to
the function for as long as α lives.
This is the dual of the caller’s point of view: the abstraction contains
two mutable borrows ℓ⁰ₓ and ℓ⁰ᵧ, whose loans are not in the environment;
they stand for the values we consumed upon calling the function.
The abstraction also contains two mutable loans ℓₓ and ℓᵧ, associated to the
borrows of the input values <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>.
Importantly, we attach a continuation that we will use for the synthesis, and
which is currently the identity; intuitively, this means that ℓ⁰ₓ and ℓₓ are
actually the same (and similarly for ℓ⁰ᵧ and ℓᵧ). The link between borrows
and loans inside the input region abstraction will become more complex as we
proceed through the synthesis.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A_input(α) {
    MB ℓ⁰ₓ (_),
    MB ℓ⁰ᵧ (_),
    ML ℓₓ,
    ML ℓᵧ,
} ⟦ (ℓ⁰ₓ, ℓ⁰ᵧ): λ ℓₓ ℓᵧ ⇒ (ℓₓ, ℓᵧ) ⟧

b ↦ σ_b
x ↦ MB ℓₓ (σₓ : T)
y ↦ MB ℓᵧ (σᵧ : T)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">choose</span>
  <span class="err">{</span><span class="n">T</span> : <span class="kt">Type</span><span class="err">}</span> (<span class="n">b</span> : <span class="n">Bool</span>) (<span class="n">x</span> <span class="n">y</span> : <span class="n">T</span>) :
  <span class="n">Result</span> (<span class="n">T</span> <span class="o">×</span> (<span class="n">T</span> <span class="o">→</span> (<span class="n">T</span> <span class="o">×</span> <span class="n">T</span>))) := <span class="n">do</span>
  [<span class="o">.</span>]
</code></pre></div></div>

<p>We then evaluate the <code class="language-plaintext highlighter-rouge">if</code>, branching over the symbolic value σ_b.
We duplicate the environment and substitute σ_b with <code class="language-plaintext highlighter-rouge">true</code> for the first
branch, and <code class="language-plaintext highlighter-rouge">false</code> for the second branch.
Below, we show the environment for the first branch of the <code class="language-plaintext highlighter-rouge">if</code>:</p>

<p><strong>Environment (first branch):</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A_input(α) {
    MB ℓ⁰ₓ (_),
    MB ℓ⁰ᵧ (_),
    ML ℓₓ,
    ML ℓᵧ,
} ⟦ (ℓ⁰ₓ, ℓ⁰ᵧ): λ ℓₓ ℓᵧ ⇒ (ℓₓ, ℓᵧ) ⟧

b ↦ true
x ↦ MB ℓₓ (σₓ : T)
y ↦ MB ℓᵧ (σᵧ : T)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">choose</span>
  <span class="err">{</span><span class="n">T</span> : <span class="kt">Type</span><span class="err">}</span> (<span class="n">b</span> : <span class="n">Bool</span>) (<span class="n">x</span> <span class="n">y</span> : <span class="n">T</span>) :
  <span class="n">Result</span> (<span class="n">T</span> <span class="o">×</span> (<span class="n">T</span> <span class="o">→</span> (<span class="n">T</span> <span class="o">×</span> <span class="n">T</span>))) := <span class="n">do</span>
  <span class="n">if</span> <span class="n">b</span> <span class="n">then</span> [<span class="o">.</span>]
  <span class="n">else</span> [<span class="o">.</span>]
</code></pre></div></div>

<p>We proceed with the evaluation of the first branch. Upon reaching <code class="language-plaintext highlighter-rouge">x_ret = move x</code>,
we move <code class="language-plaintext highlighter-rouge">x</code> to the return variable; the synthesized code is left unchanged.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A_input(α) {
    MB ℓ⁰ₓ (_),
    MB ℓ⁰ᵧ (_),
    ML ℓₓ,
    ML ℓᵧ,
} ⟦ (ℓ⁰ₓ, ℓ⁰ᵧ): λ ℓₓ ℓᵧ ⇒ (ℓₓ, ℓᵧ) ⟧

b     ↦ true
x     ↦ ⊥
y     ↦ MB ℓᵧ (σᵧ : T)
x_ret ↦ MB ℓₓ (σₓ : T)
</code></pre></div></div>

<p>We then reach the <code class="language-plaintext highlighter-rouge">return</code>. This is the crucial part of the translation. We
need to transform the environment so that it matches a target environment given
by the signature of <code class="language-plaintext highlighter-rouge">choose</code>. In the process, we will introduce and merge
region abstractions, thus progressively synthesizing the backward function for
the first branch of the <code class="language-plaintext highlighter-rouge">if</code>.</p>

<p>We first move the values of <code class="language-plaintext highlighter-rouge">b</code> and <code class="language-plaintext highlighter-rouge">y</code> to anonymous values, and eliminate the
value of <code class="language-plaintext highlighter-rouge">b</code> as it doesn’t contain any borrows; this has no effect on the
synthesis. We then transform the borrow moved from <code class="language-plaintext highlighter-rouge">y</code> into a region
abstraction A₀. This region abstraction has no inputs, as it doesn’t contain
mutable loans, and a single output, the value to give back for the mutable
borrow ℓᵧ; we thus attach a continuation stating that upon ending A₀ we
retrieve a value for ℓᵧ, which is actually σᵧ.</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A_input(α) {
    MB ℓ⁰ₓ (_),
    MB ℓ⁰ᵧ (_),
    ML ℓₓ,
    ML ℓᵧ,
} ⟦ (ℓ⁰ₓ, ℓ⁰ᵧ): λ ℓₓ ℓᵧ ⇒ (ℓₓ, ℓᵧ) ⟧

b     ↦ ⊥
x     ↦ ⊥
y     ↦ ⊥
x_ret ↦ MB ℓₓ (σₓ : T)

A₀ {
    MB ℓᵧ (_)
} ⟦ ℓᵧ: σᵧ ⟧
</code></pre></div></div>

<p>We perform one last step by merging A_input(α) and A₀ together. Merging the
content of region abstractions is done as before; in particular the borrow and
the loan for ℓᵧ cancel out. Merging two region abstractions also requires
composing their continuations. Importantly, the fact that a borrow and a loan
cancel out is mirrored by the fact that the continuation of A_input(α) consumes
a borrow (ℓᵧ) which is actually an output of A₀. The resulting continuation of
A_input(α) thus only has one input, the value consumed upon ending ℓₓ.</p>

<p>This yields an environment which matches our target environment: <code class="language-plaintext highlighter-rouge">x_ret</code> maps
to a valid borrow, all the other local variables map to ⊥, and we have a
single region abstraction for α which acts as an interface between the caller
and the callee. We can thus end the translation of the first branch: the
returned value is the value inside <code class="language-plaintext highlighter-rouge">x_ret</code> (i.e., σₓ) while the backward
function is given by the continuation attached to A_input(α).</p>

<p><strong>Environment:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A_input(α) {
    MB ℓ⁰ₓ (_),
    MB ℓ⁰ᵧ (_),
    ML ℓₓ,
} ⟦ (ℓ⁰ₓ, ℓ⁰ᵧ): λ ℓₓ ⇒ (ℓₓ, σᵧ) ⟧

b     ↦ ⊥
x     ↦ ⊥
y     ↦ ⊥
x_ret ↦ MB ℓₓ (σₓ : T)
</code></pre></div></div>

<p><strong>Synthesized code:</strong></p>
<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">choose</span>
  <span class="err">{</span><span class="n">T</span> : <span class="kt">Type</span><span class="err">}</span> (<span class="n">b</span> : <span class="n">Bool</span>) (<span class="n">x</span> <span class="n">y</span> : <span class="n">T</span>) :
  <span class="n">Result</span> (<span class="n">T</span> <span class="o">×</span> (<span class="n">T</span> <span class="o">→</span> (<span class="n">T</span> <span class="o">×</span> <span class="n">T</span>))) := <span class="n">do</span>
  <span class="n">if</span> <span class="n">b</span> <span class="n">then</span> <span class="n">ok</span> (<span class="n">x</span>, <span class="k">fun</span> <span class="n">x0</span> <span class="o">=&gt;</span> (<span class="n">x0</span>, <span class="n">y</span>))
  <span class="n">else</span> [<span class="o">.</span>]
</code></pre></div></div>

<p>The translation of the second branch is similar; we omit it.</p>

<h2 id="soundness">Soundness</h2>

<p>We claimed that a symbolic interpreter for LLBC implements a borrow-checker for
Rust; we now summarize the formal argument that substantiates this claim.
The full details are in the ICFP 2024 paper and my thesis manuscript.</p>

<p>The soundness of LLBC’s symbolic semantics (LLBCS) is predicated on the LLBC
model being a sound foundation. LLBC has several unusual features, such as
attaching values to pointers rather than to the underlying memory location, or
not relying on an explicit heap; it therefore requires a formal argument to
establish that this is an acceptable way to model Rust programs. We remark that
this question is orthogonal to the RustBelt line of work: RustBelt establishes
the soundness of Rust’s type system with regards to λ_Rust, whose classic,
unsurprising semantics does not warrant scrutiny. Clarifying the link between
LLBC and a standard heap-and-addresses model is not just a matter of theory:
once the Rust compiler emits LLVM bitcode, the heap and addresses become real.</p>

<p>We address this question in two steps:</p>

<ol>
  <li>
    <p>We introduce PL, for “pointer language”, which uses a traditional, explicit
heap inspired by CompCert’s C memory model, and show that it refines LLBC.
This establishes that a low-level model (where values live at a given
address) refines the Rust model given by LLBC (where borrows hold the value
they are borrowing).</p>
  </li>
  <li>
    <p>We prove that LLBC itself refines the symbolic version of LLBC (LLBCS).
Combined with the previous result, this allows us to precisely state why
LLBCS is a borrow-checker for LLBC: if an LLBCS execution succeeds, then any
corresponding low-level PL execution is safe for all inputs.</p>
  </li>
</ol>

<p>More precisely, a program which is successfully evaluated following the symbolic
semantics is <em>memory safe</em>, and its evaluation following the semantics of LLBC
is in <em>bisimulation</em> with an evaluation using the heap-based PL semantics.</p>

<p>To conduct these proofs of refinement, we introduce a novel proof technique that
relies on the fact that our languages operate over the same grammar of
expressions, but give it different <em>meanings</em>, or <em>views</em>. Rather than go
full-throttle with a standard compilation-style proof of simulation, we reason
modularly over local or pointwise transformations that rewrite one piece of
state to another — proofs over those elementary transformations are much easier.
We then show that two states that are related by the transitive closure of these
elementary transformations continue to relate throughout their execution,
ultimately giving a proof of refinement.</p>

<p>We note that the functional translation is currently trusted: its correctness is
not yet formally established, and is left as future work.</p>

<p>Finally, there is an ongoing effort to mechanize these proofs, which are
currently pen-and-paper. The goal is to obtain a machine-checked formalization
of the soundness of LLBCS as a borrow-checker.</p>

<h2 id="beyond-the-rust-borrow-checker">Beyond the Rust Borrow-Checker</h2>

<p>Because our approach to borrow-checking is semantic rather than syntactic, Aeneas
can actually borrow-check (and translate) programs which are not accepted by
Rust’s current borrow checker.</p>

<h3 id="a-limitation-of-rusts-borrow-checker">A Limitation of Rust’s Borrow-Checker</h3>

<p>In the process of testing Aeneas on B-epsilon trees, we bumped into a limitation
of the current Rust borrow-checking algorithm. The <code class="language-plaintext highlighter-rouge">get_suffix_at_x</code> function
below looks for an element in a list and returns a mutable borrow to the suffix
starting at that element. The current Rust borrow-checker is too coarse to
notice that the <code class="language-plaintext highlighter-rouge">Cons</code> branch is valid. More specifically, it considers that the
reborrows performed through <code class="language-plaintext highlighter-rouge">hd</code> and <code class="language-plaintext highlighter-rouge">tl</code> should last until the end of the
lexical scope, that is, until the end of the <code class="language-plaintext highlighter-rouge">Cons</code> branch.</p>

<p>Instead, one may notice that it is possible to end those borrows earlier, after
evaluating the conditional, in order to retrieve full ownership of the value
borrowed by <code class="language-plaintext highlighter-rouge">ls</code> in the first branch of the <code class="language-plaintext highlighter-rouge">if</code>, and make the example
borrow-check. The ongoing replacement of the borrow-checker in Rust, named
Polonius, implements a more refined lifetime analysis and accepts this program.</p>

<p>More interestingly, our semantic approach of borrows makes this program
borrow-check without issues; since our discipline is based on symbolic execution
and a semantic approach to loans, we accept the example without troubles, and
are resilient to further syntactic tweaks of the program.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">get_suffix_at_x</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span><span class="n">ls</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">List</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="n">List</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="k">match</span> <span class="n">ls</span> <span class="p">{</span>
    <span class="nb">Nil</span> <span class="k">=&gt;</span> <span class="p">{</span> <span class="n">ls</span> <span class="p">}</span>
    <span class="nf">Cons</span><span class="p">(</span><span class="n">hd</span><span class="p">,</span> <span class="n">tl</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span> <span class="c1">// error: first mutable borrow occurs here</span>
      <span class="k">if</span> <span class="o">*</span><span class="n">hd</span> <span class="o">==</span> <span class="n">x</span> <span class="p">{</span> <span class="n">ls</span> <span class="c1">// second mutable borrow occurs here</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nf">get_suffix_at_x</span><span class="p">(</span><span class="n">tl</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span>
</code></pre></div></div>

<h3 id="precise-reborrows">Precise Reborrows</h3>

<p>Because of the way we handle reborrows, there are actually cases of programs
deemed invalid even by Polonius, but supported by Aeneas.</p>

<p>In the example below, we first create a shared borrow that we store in <code class="language-plaintext highlighter-rouge">pp</code>,
then a reborrow of a subvalue borrowed by <code class="language-plaintext highlighter-rouge">pp</code> that we store in <code class="language-plaintext highlighter-rouge">px</code>. Upon
evaluating the assignment <code class="language-plaintext highlighter-rouge">p.1 = 2</code>, <code class="language-plaintext highlighter-rouge">px</code> simply maps to a shared borrow of the
first component of <code class="language-plaintext highlighter-rouge">p</code>. Importantly, even though <code class="language-plaintext highlighter-rouge">px</code> reborrows part of <code class="language-plaintext highlighter-rouge">pp</code>,
there are no links between <code class="language-plaintext highlighter-rouge">px</code> and <code class="language-plaintext highlighter-rouge">pp</code>: our semantics does not track the
hierarchy between borrows and their subsequent reborrows. In other words,
<code class="language-plaintext highlighter-rouge">let px = &amp;(*pp.0)</code> is equivalent to <code class="language-plaintext highlighter-rouge">let px = &amp;p.0</code>, where we borrow directly
from <code class="language-plaintext highlighter-rouge">p</code> without resorting to <code class="language-plaintext highlighter-rouge">pp</code>. This implies that, upon ending the borrow
ℓ_p stored in <code class="language-plaintext highlighter-rouge">pp</code> at the assignment, we do not need to end ℓ_x stored in <code class="language-plaintext highlighter-rouge">px</code>,
which in turn allows us to legally evaluate the assertion.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">p</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">let</span> <span class="n">pp</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">p</span><span class="p">;</span>
<span class="c1">// p  ↦ SL ℓ_p (0, 1)</span>
<span class="c1">// pp ↦ SB ℓ_p</span>
<span class="k">let</span> <span class="n">px</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">(</span><span class="o">*</span><span class="n">pp</span><span class="na">.0</span><span class="p">);</span>
<span class="c1">// p  ↦ SL ℓ_p (SL ℓ_x 0, 1)</span>
<span class="c1">// pp ↦ SB ℓ_p</span>
<span class="c1">// px ↦ SB ℓ_x</span>
<span class="n">p</span><span class="na">.1</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="c1">// p  ↦ (SL ℓ_x 0, 2)</span>
<span class="c1">// pp ↦ ⊥</span>
<span class="c1">// px ↦ SB ℓ_x</span>
<span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">px</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
</code></pre></div></div>

<p>When we attempt to borrow-check this program (with Polonius or the current
implementation of the borrow checker), the Rust borrow checker considers that
<code class="language-plaintext highlighter-rouge">px</code> reborrows <code class="language-plaintext highlighter-rouge">pp</code>, and thus needs to end before <code class="language-plaintext highlighter-rouge">pp</code> ends.</p>

<p>The code snippet below illustrates a similar example with mutable borrows.
We create a borrow <code class="language-plaintext highlighter-rouge">px1</code> of (the value of) <code class="language-plaintext highlighter-rouge">x</code>, then reborrow this value
through <code class="language-plaintext highlighter-rouge">px2</code>. We then update <code class="language-plaintext highlighter-rouge">px1</code> to borrow <code class="language-plaintext highlighter-rouge">y</code>. At this point, <code class="language-plaintext highlighter-rouge">px2</code> still
borrows <code class="language-plaintext highlighter-rouge">x</code>. The important point to notice is that upon performing this update,
we remember the old value of <code class="language-plaintext highlighter-rouge">px1</code> in an anonymous variable to not lose
information about the borrow graph. Similarly to the previous example with
shared borrows, the resulting environment doesn’t track the fact that <code class="language-plaintext highlighter-rouge">px2</code> was
created by reborrowing the value initially borrowed by <code class="language-plaintext highlighter-rouge">px1</code>: there are no links
between those two variables. Consequently, upon ending borrow ℓ_y (stored in
<code class="language-plaintext highlighter-rouge">px1</code>) to access <code class="language-plaintext highlighter-rouge">y</code>, we don’t need to end ℓ₂ (stored in <code class="language-plaintext highlighter-rouge">px2</code>). This in
return allows us to legally dereference <code class="language-plaintext highlighter-rouge">px2</code> at the end.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">px1</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">;</span>
<span class="k">let</span> <span class="n">px2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">(</span><span class="o">*</span><span class="n">px1</span><span class="p">);</span> <span class="c1">// Reborrow: px2 now borrows (the value of) x</span>
<span class="c1">// x   ↦ ML ℓ₁</span>
<span class="c1">// px1 ↦ MB ℓ₁ (ML ℓ₂)</span>
<span class="c1">// px2 ↦ MB ℓ₂ 0</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">px1</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">y</span><span class="p">;</span> <span class="c1">// Update px1 to borrow y instead of x</span>
<span class="c1">// x   ↦ ML ℓ₁</span>
<span class="c1">// _   ↦ MB ℓ₁ (ML ℓ₂)</span>
<span class="c1">// px2 ↦ MB ℓ₂ 0</span>
<span class="c1">// y   ↦ ML ℓ_y</span>
<span class="c1">// px1 ↦ MB ℓ_y 1</span>
<span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">px1</span> <span class="o">==</span> <span class="mi">1</span><span class="p">);</span>
<span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">px2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
<span class="nd">assert!</span><span class="p">(</span><span class="n">y</span> <span class="o">==</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// End the borrow of y through px1 (shouldn't impact px2!)</span>
<span class="c1">// x   ↦ ML ℓ₁</span>
<span class="c1">// _   ↦ MB ℓ₁ (ML ℓ₂)</span>
<span class="c1">// px2 ↦ MB ℓ₂ 0</span>
<span class="c1">// y   ↦ 1</span>
<span class="c1">// px1 ↦ ⊥</span>
<span class="nd">assert!</span><span class="p">(</span><span class="o">*</span><span class="n">px2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// Considered invalid by rustc, but accepted by Aeneas</span>
</code></pre></div></div>

<p>The two examples above exemplify cases where both the Rust borrow checker and
Polonius deem a program as invalid, while Aeneas accepts it. We do not claim
that this is a strong limitation of the Rust borrow checker: these use cases
seem quite anecdotal and are probably useless in practice. However, we believe
the ability of Aeneas to precisely capture the behavior of such use cases
supports our claim that our semantics really captures the essence of the borrow
mechanism.</p>

<p>More examples of programs rejected by the Rust compiler but accepted by Aeneas
can be found in the
<a href="https://github.com/AeneasVerif/aeneas/blob/main/tests/src/rust-borrow-check-issues.rs">test suite</a>.</p>

<h2 id="verifying-rust-programs-with-aeneas">Verifying Rust Programs with Aeneas</h2>

<p>Aeneas is being used in practice to verify real-world Rust code. In particular,
Microsoft is using Aeneas to verify implementations of the
<a href="https://github.com/microsoft/SymCrypt">SymCrypt</a> cryptographic library, as
described in their
<a href="https://www.microsoft.com/en-us/research/blog/rewriting-symcrypt-in-rust-to-modernize-microsofts-cryptographic-library/">blog post</a>.
We now showcase the verification workflow through a few examples.</p>

<h3 id="a-simple-arithmetic-example">A Simple Arithmetic Example</h3>

<p>Consider <code class="language-plaintext highlighter-rouge">mul2_add1</code>, which Aeneas translates as follows:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">mul2_add1</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
    <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">mul2_add1</span> (<span class="n">x</span> : <span class="n">U32</span>) : <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> <span class="n">x1</span> <span class="err">←</span> <span class="n">x</span> <span class="o">+</span> <span class="n">x</span>
  <span class="n">let</span> <span class="n">x2</span> <span class="err">←</span> <span class="n">x1</span> <span class="o">+</span> <span class="mi">1</span><span class="n">#u32</span>
  <span class="n">ok</span> <span class="n">x2</span>
</code></pre></div></div>

<p>Le us show how to prove that <code class="language-plaintext highlighter-rouge">mul2_add1</code> evaluates to <code class="language-plaintext highlighter-rouge">2 * x + 1</code> provided there is no overflow.
We write specifications in the Hoare-logic style: <code class="language-plaintext highlighter-rouge">mul2_add1 x ⦃ y =&gt; y.val = 2 * x.val + (1 : Nat) ⦄</code>
below means that <code class="language-plaintext highlighter-rouge">mul2_add1 x</code> successfully evaluates to some value <code class="language-plaintext highlighter-rouge">y</code> (in particular, it doesn’t panic)
that satisfies <code class="language-plaintext highlighter-rouge">y.val = 2 * x.val + 1</code> (<code class="language-plaintext highlighter-rouge">x.val</code> means <code class="language-plaintext highlighter-rouge">x</code> seen as an unbounded mathematical integer).</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">theorem</span> <span class="n">mul2_add1_spec</span> (<span class="n">x</span> : <span class="n">U32</span>) (<span class="n">h</span> : <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">≤</span> <span class="n">U32</span><span class="o">.</span><span class="n">max</span>) :
  <span class="n">mul2_add1</span> <span class="n">x</span> <span class="err">⦃</span> <span class="n">y</span> <span class="o">=&gt;</span> <span class="n">y</span><span class="o">.</span><span class="n">val</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> <span class="mi">1</span> <span class="err">⦄</span> := <span class="k">by</span>
  <span class="n">unfold</span> <span class="n">mul2_add1</span>
  <span class="n">progress</span> <span class="n">as</span> <span class="o">⟨</span> <span class="n">i</span> <span class="o">⟩</span>
  <span class="n">progress</span> <span class="n">as</span> <span class="o">⟨</span> <span class="n">i</span><span class="err">'</span> <span class="o">⟩</span>
  <span class="n">scalar_tac</span>
</code></pre></div></div>

<p>Initially, Lean shows us the following goal to be proven:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x : U32
h : 2 * x.val + 1 ≤ U32.max
⊢ mul2_add1 x ⦃ y =&gt; y.val = 2 * x.val + 1 ⦄
</code></pre></div></div>

<p>Proving that this holds looks a lot like a debugging session: the first thing we need to do
is dive into the body of <code class="language-plaintext highlighter-rouge">unfold mul2_add1</code>. We can do so with the <code class="language-plaintext highlighter-rouge">unfold</code> tactic (“tactic” is the
name of the instructions that are used to guide the proofs), revealing:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x : U32
h : 2 * x.val + 1 ≤ U32.max
⊢ (do
    let x1 ← x + x
    let x2 ← x1 + 1#u32
    ok x2) ⦃
  y =&gt; y.val = 2 * x.val + 1 ⦄
</code></pre></div></div>

<p>We now need to step through the function body and provide a dedicated tactic, <code class="language-plaintext highlighter-rouge">progress</code>.
The <code class="language-plaintext highlighter-rouge">progress</code> tactic looks at the first monadic operation in the goal, finds a
matching specification and applies it, introducing the result variable. The
<code class="language-plaintext highlighter-rouge">as ⟨ i ⟩</code> clause names it.
The first <code class="language-plaintext highlighter-rouge">progress as ⟨ i ⟩</code> processes <code class="language-plaintext highlighter-rouge">x + x</code>, proving on the fly that there is no overflow
(we have <code class="language-plaintext highlighter-rouge">x.val + x.val ≤ U32.max</code>) and updating the context accordingly:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x : U32
h : 2 * x.val + 1 ≤ U32.max
i : U32
_ : i.val = x.val + x.val
⊢ (do
    let x2 ← i + 1#u32
    ok x2) ⦃
  y =&gt; y.val = 2 * x.val + 1 ⦄
</code></pre></div></div>

<p>The second <code class="language-plaintext highlighter-rouge">progress as ⟨ i' ⟩</code> removes the second addition, leaving a pure arithmetic goal:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>i : U32
_ : i.val = x.val + x.val
i' : U32
_ : i'.val = i.val + 1
⊢ i'.val = 2 * x.val + 1
</code></pre></div></div>

<p>This goal can trivially be solved by using an arithmetic solver (<code class="language-plaintext highlighter-rouge">scalar_tac</code> in our case).</p>

<h3 id="using-registered-theorems">Using Registered Theorems</h3>

<p>Consider a caller of <code class="language-plaintext highlighter-rouge">mul2_add1</code>:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">mul2_add1_add</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
    <span class="nf">mul2_add1</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="n">y</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">use_mul2_add1</span> (<span class="n">x</span> : <span class="n">U32</span>) (<span class="n">y</span> : <span class="n">U32</span>) : <span class="n">Result</span> <span class="n">U32</span> := <span class="n">do</span>
  <span class="n">let</span> <span class="n">x1</span> <span class="err">←</span> <span class="n">mul2_add1</span> <span class="n">x</span>
  <span class="n">x1</span> <span class="o">+</span> <span class="n">y</span>
</code></pre></div></div>

<p>When doing the proof, we want to reuse the specification we just proved for <code class="language-plaintext highlighter-rouge">mul2_add1</code>.
We can do so by explicitly instructing <code class="language-plaintext highlighter-rouge">progress</code> to use <code class="language-plaintext highlighter-rouge">mul2_add1_spec</code> through the
<code class="language-plaintext highlighter-rouge">with</code> keyword: <code class="language-plaintext highlighter-rouge">progress with mul2_add1_spec</code>. Even better, if we mark <code class="language-plaintext highlighter-rouge">mul2_add1_spec</code>
with the <code class="language-plaintext highlighter-rouge">@[progress]</code> attribute, <code class="language-plaintext highlighter-rouge">progress</code> can automatically look it up when encountering
<code class="language-plaintext highlighter-rouge">mul2_add1</code>. This looks like this:</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">@</span>[<span class="n">progress</span>]
<span class="k">theorem</span> <span class="n">mul2_add1_spec</span> (<span class="n">x</span> : <span class="n">U32</span>) (<span class="n">h</span> : <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">≤</span> <span class="n">U32</span><span class="o">.</span><span class="n">max</span>) :
  <span class="n">mul2_add1</span> <span class="n">x</span> <span class="err">⦃</span> <span class="n">y</span> <span class="o">=&gt;</span> <span class="n">y</span><span class="o">.</span><span class="n">val</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> <span class="mi">1</span> <span class="err">⦄</span> := <span class="k">by</span>
  <span class="o">...</span>

<span class="k">theorem</span> <span class="n">use_mul2_add1_spec</span> (<span class="n">x</span> : <span class="n">U32</span>) (<span class="n">y</span> : <span class="n">U32</span>)
  (<span class="n">h</span> : <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">y</span><span class="o">.</span><span class="n">val</span> <span class="o">≤</span> <span class="n">U32</span><span class="o">.</span><span class="n">max</span>) :
  <span class="n">use_mul2_add1</span> <span class="n">x</span> <span class="n">y</span> <span class="err">⦃</span> <span class="n">z</span> <span class="o">=&gt;</span> <span class="n">z</span><span class="o">.</span><span class="n">val</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> (<span class="mi">1</span> : <span class="n">Nat</span>) <span class="o">+</span> <span class="n">y</span><span class="o">.</span><span class="n">val</span> <span class="err">⦄</span> := <span class="k">by</span>
  <span class="n">unfold</span> <span class="n">use_mul2_add1</span>
  <span class="n">progress</span> <span class="n">as</span> <span class="o">⟨</span> <span class="n">i</span> <span class="o">⟩</span><span class="cd">    -- automatically uses mul2_add1_spec</span>
  <span class="n">progress</span> <span class="n">as</span> <span class="o">⟨</span> <span class="n">i</span><span class="err">'</span> <span class="o">⟩</span>
  <span class="n">scalar_tac</span>
</code></pre></div></div>

<h3 id="constant-time-modular-addition">Constant-Time Modular Addition</h3>

<p>Let’s now look at a real example.</p>

<p>Cryptographic code often requires constant-time implementations to prevent
side-channel attacks: if the execution time of a cryptographic operation depends
on the value of a secret key, an attacker can measure that time across many invocations
and statistically recover the key. For this reason, cryptographic
implementations must avoid branches and data-dependent operations that would
cause the execution time to vary depending on the value of their secret inputs.</p>

<p>The following example appears in the SymCrypt implementation of ML-KEM, where we
need to do operations modulo prime number 3329.
In particular,  given <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code> two numbers smaller than (the prime number) 3329,
the following function computes <code class="language-plaintext highlighter-rouge">(a + b) % 3329</code>.
It cannot use <code class="language-plaintext highlighter-rouge">%</code> — the division and conditional branch would produce
variable-time code. Instead, the implementation uses a branchless trick based
on underflow and bitmasking:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">mod_add</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">a</span> <span class="o">&lt;</span> <span class="mi">3329</span><span class="p">);</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">b</span> <span class="o">&lt;</span> <span class="mi">3329</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>                  <span class="c1">// 0 &lt;= a + b &lt;= 2 * 3328</span>
    <span class="k">let</span> <span class="n">res</span> <span class="o">=</span> <span class="n">sum</span><span class="nf">.wrapping_sub</span><span class="p">(</span><span class="mi">3329</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">mask</span> <span class="o">=</span> <span class="n">res</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">;</span>             <span class="c1">// mask = 0xffff if a + b &lt; 3329, 0 otherwise</span>
    <span class="k">let</span> <span class="n">q</span> <span class="o">=</span> <span class="mi">3329</span> <span class="o">&amp;</span> <span class="n">mask</span><span class="p">;</span>              <span class="c1">// q = 3329 if a + b &lt; 3329, 0 otherwise</span>
    <span class="n">res</span><span class="nf">.wrapping_add</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Because of properties of the modulo, either <code class="language-plaintext highlighter-rouge">a + b</code> is smaller than 3329, in which
case <code class="language-plaintext highlighter-rouge">(a + b) % 3329 = a + b</code>, or it is greater, in which case we have:
<code class="language-plaintext highlighter-rouge">(a + b) % 3329 = a + b - 3329</code>.
This means that computing the modulo simply requires conditionally subtracting 3329.
Same as with the modulo operation, we can not branch on <code class="language-plaintext highlighter-rouge">a + b &lt; 3329</code>, as it would 
lead to non-constant time code revealing information about <code class="language-plaintext highlighter-rouge">a + b</code> (the branches of the
<code class="language-plaintext highlighter-rouge">if then else</code> would not require the same number of instructions to execute, not even
mentioning the problem of speculative execution).
The trick is to always subtract 3329, then use the result to conditionally add 3329 back
in case we didn’t have to do the subtraction in the first place.
This works because in case the subtraction was not needed (i.e., <code class="language-plaintext highlighter-rouge">a + b &lt; 3329</code>)
<code class="language-plaintext highlighter-rouge">wrapping_sub</code> underflows: <code class="language-plaintext highlighter-rouge">res</code> wraps to a large value
whose upper bits are set, so the right shift yields <code class="language-plaintext highlighter-rouge">0xffff</code>. Then
<code class="language-plaintext highlighter-rouge">q = 3329 &amp; 0xffff = 3329</code>, and adding it back wraps around to <code class="language-plaintext highlighter-rouge">sum</code>.
In the other case (<code class="language-plaintext highlighter-rouge">a + b &lt; 3329</code>), the shift gives a mask equal to 0, meaning <code class="language-plaintext highlighter-rouge">wrapping_add</code> adds 0.
In both cases the result is <code class="language-plaintext highlighter-rouge">(a + b) % 3329</code>, without any branch.</p>

<p>Aeneas translates this to:</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="n">mod_add</span> (<span class="n">a</span> : <span class="n">Std</span><span class="o">.</span><span class="n">U32</span>) (<span class="n">b</span> : <span class="n">Std</span><span class="o">.</span><span class="n">U32</span>) : <span class="n">Result</span> <span class="n">Std</span><span class="o">.</span><span class="n">U32</span> := <span class="n">do</span>
  <span class="n">massert</span> (<span class="n">a</span> <span class="o">&lt;</span> <span class="mi">3329</span><span class="n">#u32</span>)
  <span class="n">massert</span> (<span class="n">b</span> <span class="o">&lt;</span> <span class="mi">3329</span><span class="n">#u32</span>)
  <span class="n">let</span> <span class="n">sum</span> <span class="err">←</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
  <span class="n">let</span> <span class="n">res</span> <span class="err">←</span> <span class="n">lift</span> (<span class="n">core</span><span class="o">.</span><span class="n">num</span><span class="o">.</span><span class="n">U32</span><span class="o">.</span><span class="n">wrapping_sub</span> <span class="n">sum</span> <span class="mi">3329</span><span class="n">#u32</span>)
  <span class="n">let</span> <span class="n">mask</span> <span class="err">←</span> <span class="n">res</span> <span class="o">&gt;&gt;&gt;</span> <span class="mi">16</span><span class="n">#i32</span>
  <span class="n">let</span> <span class="n">q</span> <span class="err">←</span> <span class="n">lift</span> (<span class="mi">3329</span><span class="n">#u32</span> <span class="o">&amp;&amp;&amp;</span> <span class="n">mask</span>)
  <span class="n">ok</span> (<span class="n">core</span><span class="o">.</span><span class="n">num</span><span class="o">.</span><span class="n">U32</span><span class="o">.</span><span class="n">wrapping_add</span> <span class="n">res</span> <span class="n">q</span>)
</code></pre></div></div>

<p>The correctness proof is:</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">theorem</span> <span class="n">mod_add</span><span class="o">.</span><span class="n">spec</span> (<span class="n">x</span> <span class="n">y</span> : <span class="n">U32</span>) (<span class="n">h</span> : <span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">&lt;</span> <span class="mi">3329</span> <span class="o">∧</span> <span class="n">y</span><span class="o">.</span><span class="n">val</span> <span class="o">&lt;</span> <span class="mi">3329</span>) :
  <span class="n">mod_add</span> <span class="n">x</span> <span class="n">y</span> <span class="err">⦃</span> <span class="n">z</span> <span class="o">=&gt;</span> <span class="n">z</span><span class="o">.</span><span class="n">val</span> <span class="o">=</span> (<span class="n">x</span><span class="o">.</span><span class="n">val</span> <span class="o">+</span> <span class="n">y</span><span class="o">.</span><span class="n">val</span>) <span class="err">%</span> <span class="mi">3329</span> <span class="err">⦄</span> := <span class="k">by</span>
  <span class="n">unfold</span> <span class="n">mod_add</span>
  <span class="n">progress</span><span class="o">*</span>
  <span class="n">bv_tac</span> <span class="mi">32</span>
</code></pre></div></div>

<p>Rather than calling <code class="language-plaintext highlighter-rouge">progress</code> step by step, <code class="language-plaintext highlighter-rouge">progress*</code> applies it repeatedly
until no monadic operations remain, leaving a goal containing arithmetic operations
and bit-vector operations. We provide a set of tactics and solvers to discharge
the various proof obligations encountered when verifying such code; in the present
case, it suffices to call <code class="language-plaintext highlighter-rouge">bv_tac</code>,
a bitvector decision tactic that handles the remaining bit-level reasoning.</p>

<p>One last remark: when developing proofs interactively, one often wants to go fast by means
of, e.g., <code class="language-plaintext highlighter-rouge">progress*</code>, but also have the possibility of diving into the details of the proof.
For this reason we provide <code class="language-plaintext highlighter-rouge">progress*?</code> that works like <code class="language-plaintext highlighter-rouge">progress*</code> but also generates a
detailed proof script that can be inserted in the code via VS Code code actions (one just needs
to click a button). For <code class="language-plaintext highlighter-rouge">mod_add</code>, we get:</p>

<div class="language-lean highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">let</span><span class="o">*</span> <span class="o">⟨</span> <span class="o">⟩</span> <span class="err">←</span> <span class="n">massert_spec</span>
  <span class="n">let</span><span class="o">*</span> <span class="o">⟨</span> <span class="o">⟩</span> <span class="err">←</span> <span class="n">massert_spec</span>
  <span class="n">let</span><span class="o">*</span> <span class="o">⟨</span> <span class="n">sum</span>, <span class="n">sum_post</span> <span class="o">⟩</span> <span class="err">←</span> <span class="n">U32</span><span class="o">.</span><span class="n">add_spec</span>
  <span class="n">let</span><span class="o">*</span> <span class="o">⟨</span> <span class="n">res</span>, <span class="n">res_post</span> <span class="o">⟩</span> <span class="err">←</span> <span class="n">core</span><span class="o">.</span><span class="n">num</span><span class="o">.</span><span class="n">U32</span><span class="o">.</span><span class="n">wrapping_sub</span><span class="o">.</span><span class="n">progress_spec</span>
  <span class="n">let</span><span class="o">*</span> <span class="o">⟨</span> <span class="n">mask</span>, <span class="n">mask_post1</span>, <span class="n">mask_post2</span> <span class="o">⟩</span> <span class="err">←</span> <span class="n">U32</span><span class="o">.</span><span class="n">ShiftRight_IScalar_spec</span>
  <span class="n">let</span><span class="o">*</span> <span class="o">⟨</span> <span class="n">q</span>, <span class="n">q_post1</span>, <span class="n">q_post2</span> <span class="o">⟩</span> <span class="err">←</span> <span class="n">UScalar</span><span class="o">.</span><span class="n">and_spec</span>
</code></pre></div></div>

<p>Notation <code class="language-plaintext highlighter-rouge">let* ⟨ x ⟩ ← spec</code> is syntactic sugar for <code class="language-plaintext highlighter-rouge">progress with spec as ⟨ x ⟩</code>.
After these steps, only the pure bitvector goal remains.</p>]]></content><author><name></name></author><category term="verification" /><category term="rust" /><summary type="html"><![CDATA[An Overview of the Aeneas Rust Verification Toolchain]]></summary></entry><entry><title type="html">Sculpting a Head with ZBrush</title><link href="https://www.sonho.fr//2022/12/26/sculpted-head.html" rel="alternate" type="text/html" title="Sculpting a Head with ZBrush" /><published>2022-12-26T00:00:00+00:00</published><updated>2022-12-26T00:00:00+00:00</updated><id>https://www.sonho.fr//2022/12/26/sculpted-head</id><content type="html" xml:base="https://www.sonho.fr//2022/12/26/sculpted-head.html"><![CDATA[<!-- For some reason, we can't put images in the _posts directory: I thus
     put them in the /assets directory, and use the following variable to
     make the links less cumbersome to write -->

<p>I recently decided to create a logo for my project
<a href="https://github.com/AeneasVerif/aeneas">Aeneas</a>. I knew creating logos requires
a specific set of skills but really wanted to give it a try:
what about sketching some concept on pen and paper, then vectorizing it on
computer?  It proved even harder than I had expected: after spending a couple of
evenings using various techniques to sketch ideas which all ended up in the
garbage bin, I completely discarded the idea of doing something in
2D. Definitely too hard for now, especially as I don’t have a clear idea of what
I want to achieve.</p>

<p>I then got the following idea: what about doing some sort of an antique coin,
with a sculpted profile? I could model the coin in 3D then stylize the render a
bit. That would actually be an excellent opportunity of going back to 3D
sculpting, which is something I hadn’t done in many, many years. I had also just
replaced my &gt;12 year old graphic tablet with a new one, and 3D sculpture was a
perfect opportunity to play with it. I thus set off on this project.</p>

<p>If you don’t know what 3D sculpting looks like, here is an overview.
Traditionally, surfaces of 3D objects are modelled with triangles, which are
themselves often grouped in quads. As the modeller has to manipulate each vertex
one by one, those models often have a relatively low polycount. This polycount
varies with the topic or the context, for instance whether you model an object
for a video game or a movie quality render, which goes in the foreground or the
background, etc. For a face, I would often end up with a model made of a few
thousands triangles. In contrast, with 3D sculpting we start with a base shape,
often created with the above method, subdivide this shape a lot until it has
from hundreds of thousands to tens of millions triangles (and even more!), then
use brushes to sculpt this mesh. There exists various tools to sculpt in 3D: I
personally use <a href="https://pixologic.com/">ZBrush</a>.</p>

<p>For instance, you can see several subdivision levels of a sphere below. It
starts with 482 vertices and ends with more than 100k vertices (ZBrush doesn’t
give the polycount in triangles). Whenever the subdivision level increases,
every (quad) face is split into four, and the angle between the edges is
smoothed. At some point you actually stop noticing that the surface is made of
flat faces. Note that on low-poly models, we usually render the faces in such a
way that they <em>look</em> smooth, to hide the fact that models are actually made of a
limited number of flat faces.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/sphere-subdivid.gif" alt="Subdividing a sphere" title="Subdividing a sphere" style="" width="400" align="center" />
<figcaption>Subdividing a sphere</figcaption>
</div></p>

<p>Once there are enough polygons, we can use brushes to sculpt the model by moving
groups of vertices. For this particular project I decided to go back to basics
by using a limited selection of brushes: I did everything with the 6 brushes
shown below.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<table cellspacing="0" style="border-collapse: collapse">
<tr style="background:rgba(0,0,0,0);">
  <td style="text-align: center">
    <img src="/assets/2022-12-25-sculpted-head/standard.gif" alt="Standard Brush" title="Standard Brush" style="" width="235" align="center" />
    <figcaption>Standard brush</figcaption>
  </td>
  <td style="text-align: center">
    <img src="/assets/2022-12-25-sculpted-head/pinch.gif" alt="Pinch Brush" title="Pinch Brush" style="" width="235" align="center" />
    <figcaption>Pinch brush</figcaption>
  </td>
  <td style="text-align: center">
    <img src="/assets/2022-12-25-sculpted-head/slash.gif" alt="Slash Brush" title="Slash Brush" style="" width="235" align="center" />
    <figcaption>Slash brush</figcaption>
  </td>
</tr>
<tr style="background:rgba(0,0,0,0);">
  <td style="text-align: center">
    <img src="/assets/2022-12-25-sculpted-head/clay-buildup.gif" alt="Clay Buildup Brush" title="Clay Buildup Brush" style="" width="235" align="center" />
    <figcaption>Clay Buildup brush</figcaption>
  </td>
  <td style="text-align: center">
    <img src="/assets/2022-12-25-sculpted-head/smooth1.gif" alt="Smooth1 Brush" title="Smooth1 Brush" style="" width="235" align="center" />
    <figcaption>Smooth brush</figcaption>
  </td>
  <td style="text-align: center">
    <img src="/assets/2022-12-25-sculpted-head/flatten.gif" alt="Flatten Brush" title="Flatten Brush" style="" width="235" align="center" />
    <figcaption>Flatten brush</figcaption>
  </td>
</tr>
<caption>Using brushes</caption>
</table>
</div></p>

<p>Of course, there are plenty of brushes available by default in ZBrush. It is
also possible to tune the behavior of each brush by playing with various
parameters: the size and intensity of course, but also the stroke (see the
projection on the coin at the end of the post), or the alpha mask, which
influences the shape of the brush.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/all-brushes.jpg" alt="The default brush selection" title="The default brush selection" style="" width="900" align="center" />
<figcaption>The default brush selection in ZBrush</figcaption>
</div></p>

<p>In order to start the project, I needed a base shape from where to start
sculpting the head. I usually do all my models myself, including body parts for
the various creatures I make, but this time I wanted to start fast and
downloaded a base mesh for the head. I ended up choosing <a href="https://www.turbosquid.com/fr/3d-models/free-basic-male-head-3d-model/644257">this
one</a>
on turbosquid, by the artist
<a href="https://www.turbosquid.com/fr/Search/Artists/twiesner?fbclid=IwAR27LSdh0GAlMghkSRWtJdBb7BwhxMo2GgBUhBeGz0Sc_5GtGTi7-MHccF8">twiesner</a>:
all credits to him for this model. And I can’t thank enough those artists who make
assets such as models and textures freely available online: it helps a lot!</p>

<p>I started by using the move tool to change the morphology of the face to make it
closer to what I had in mind.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/move.gif" alt="Deforming the face with the Move brush" title="Deforming the face with the Move brush" style="" width="400" align="center" />
<figcaption>Deforming the base face with the Move brush</figcaption>
</div></p>

<p>I then worked on the details. I had to experiment a bit because I hadn’t
sculpted anything in a long time. As I wanted to create a sculpted head, I also
aimed at a stylized look. As a result, I slowly converged towards the
following process. First, I used the clay buildup brush to create the overall
shapes by adding or substracting volumes. I then used the flatten brush to make
the surfaces less roundish, and give them the look of a sculpted surface.  Of
course, I also used the smooth brush a lot between the various steps. The video
below gives a good overview of the process I applied to the various parts
of the head.</p>

<video style="float:center" width="960" height="540" controls="">
  <source src="/assets/2022-12-25-sculpted-head/standard-flatten2.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>I also used the slash brush to dig crevices, for instance at the corner of the mouth,
around the nose or the eyes, together with the standard brush to give a
bit of roundness in some places, for instance on the eyelids. Finally, I used
the pinch brush a bit, in particular around the lips.</p>

<p>You can see some of the sculpting steps below: I placed the general
shapes then focused on the details (mouth, nose, eyes, ears, etc.), regularly
switching from one part to the other and progressively polishing the surfaces.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/sculpt-head.gif" alt="Sculpting the head" title="Sculpting the head" style="" width="600" align="center" />
<figcaption>Sculpting the head</figcaption>
</div></p>

<p><!-- TODO: put that in the CSS --></p>
<p><div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">

  <p>
  <b>When I draw,</b> I generally reproduce a subject I have under my eyes and
  focus on the <i>way</i> I reproduce it: by stylizing it, simplifying it, etc.
  In contrast, when I do 3D modelling, I generally don't reproduce a specific
  subject but rather invent something. This doesn't mean that I don't use
  references of course, and I pay attention to anatomy a lot.
  </p>
  
  <p><div style="text-align: center; margin: 0; caption-side: bottom">
  <img src="/assets/2022-12-25-sculpted-head/muscles.jpg" alt="Face muscles" title="Face muscles" style="" width="500" align="center" />
  <figcaption>Some face muscles</figcaption>
  </div></p>

  <p>
  There are definitely too many bones and muscles in a human face (42 muscles!).
  When sculpting I always try to keep in mind the main ones, focusing on
  plausibility rather than exactitude. In the present case I think it overall
  looks ok, meaning I probably neither forgot nor invented too many muscles...
  </p>

  </div></div></p>

<p><!-- TODO: put that in the CSS --></p>
<p><div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">

  <p>
  <b>I knew I should have closed the mouth before sculpting!</b> Using
  brushes on open edges can lead to weird results, especially in the
  presence of sharp angles. As a consequence, I ended up with the following
  artifacts at some point: as you can see, some polygons at the corner of
  the lips pointed outwards while they were supposed to point inwards.
  </p>

  <p><div style="text-align: center">
  <img src="/assets/2022-12-25-sculpted-head/mouth-pb2.jpg" alt="Mouth artifact" title="Mouth artifact" width="350" />
  <img src="/assets/2022-12-25-sculpted-head/mouth-pb1.jpg" alt="Mouth artifact" title="Mouth artifact" width="350" />
  <figcaption>Artifacts at the corner of the mouth</figcaption>
  </div></p>


  <p>
  Fortunately, I was able to fix the issue by going to the slowest subdivision
  level, switching to Blender, moving the vertices there, and finally
  propagating the changes back to ZBrush. A bit of smoothing, and everything was
  back in order.
  </p>
  </div></div></p>

<p>After doing the face, I worked on what I really dreaded: the hair. A sculpture
is supposed to be stylized, and I was really not sure about how to proceed to
capture the texture of the hair without doing too much. Again, I experimented a
bit and finally came up with the following process.  I used the standard brush
with varying sizes to create hair strands, and played with the slash brush to
add some details. By regularly switching between the two I was able to make the
hair gradually take shape. The pitch brush helped me make the tips of the hair
crisper, and at the end I used the standard brush with a bigger size to give
volume to some of the strands.</p>

<p>The alternation process between the standard brush and the slash brush is shown
in the video below.</p>

<video style="float:center" width="960" height="540" controls="">
  <source src="/assets/2022-12-25-sculpted-head/sculpt-hair.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>You can see some of the steps of sculpting the hair in the animation below:
I first created some rough strands, then added details, and finally gave them
more volume.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/sculpt-head-hair1.gif" alt="Sculpting the hair" title="Sculpting the hair" style="" width="600" align="center" />
<figcaption>Sculpting the hair</figcaption>
</div></p>

<p>Now that the head was done, I was left with the coin. Rather than using brushes
to sculpt in a free hand style, it is possible to use them to apply a single
pattern to a surface by changing the stroke (from Free Hand to Drag
Rectangle, see below). I used this technique to apply a projection of the head I had just
modelled onto a coin.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/drag-rect.jpg" alt="The drag-rect stroke" title="The drag-rect stroke" style="" width="600" align="center" />
<figcaption>The Drag Rectangle stroke</figcaption>
</div></p>

<p>I created a very simple coin model with a cylinder, then used the depth-map of
the face profile (i.e., the distance between the camera and the various points
of the head) to create an alpha texture for the standard brush. By using the
Drag Rectangle stroke, I was able to apply this projection onto the coin.
As you can see, the whiter pixels are closer to the camera, and correspond to
places of bigger volume. By using the light intensity of the depth map to control the
amount of displacement of the vertices, you can in effect project a volume
(i.e., the face) onto a surface.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/face-depth.jpg" alt="The depth map" title="The depth map" style="" height="300" align="center" />
<figcaption>The depth map</figcaption>
<img src="/assets/2022-12-25-sculpted-head/project3.gif" alt="Projecting the head" title="Projecting the head" style="" width="300" align="center" />
<figcaption>Projecting the head on a coin</figcaption>
</div></p>

<p>I then used the symmetry options to do the pourtour of the coin, before
leveraging the move tool and some other brushes to create a bit of wear and
tear. I also made a few attempts at adding finer details like erosion but
finally decided not to do so to keep the look relatively simple.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/coin-symmetry.jpg" alt="Sculpting the coin" title="Sculpting the coin" style="" width="600" align="center" />
<figcaption>Sculpting the coin by using radial symmetry</figcaption>
</div></p>

<p>I finally rendered the coin, applied a few filters and adjustments in
<a href="https://www.gimp.org/">GIMP</a> to get the current look and I was done! I hope you
enjoyed this post.</p>

<p><div style="text-align: center; margin: 0; caption-side: bottom">
<img src="/assets/2022-12-25-sculpted-head/final-coin.jpg" alt="The final logo" title="The final logo" style="" width="400" align="center" />
<figcaption>The final logo</figcaption>
</div></p>]]></content><author><name></name></author><category term="art" /><category term="cg" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Exploring Computer Graphics: Modelling an Old Town in Blender</title><link href="https://www.sonho.fr//2021/01/19/old-town.html" rel="alternate" type="text/html" title="Exploring Computer Graphics: Modelling an Old Town in Blender" /><published>2021-01-19T00:00:00+00:00</published><updated>2021-01-19T00:00:00+00:00</updated><id>https://www.sonho.fr//2021/01/19/old-town</id><content type="html" xml:base="https://www.sonho.fr//2021/01/19/old-town.html"><![CDATA[<!-- For some reason, we can't put images in the _posts directory: I thus
     put them in the /assets directory, and use the following variable to
     make the links less cumbersome to write -->

<p><a href="/assets/2021-01-19-old-town/final_render.jpg">
<img src="/assets/2021-01-19-old-town/final_render.jpg" alt="Old Town - Final Render" style="float:center" title="Old Town - Final render" />
</a></p>

<p>I recently had a look at the new release of Blender, and was amazed by the
progress made since my last use 8 years ago.
I had already been amazed by this tool when in high-school, but the
new features got me really excited: I
sometimes can’t believe an open software can be so good and powerful.
After watching a few videos and tutorials showcasing the new
features, I couldn’t resist experimenting with the new ray-tracing engine
introduced in the 2.8 version.</p>

<p><!-- TODO: put that in the CSS --></p>
<p><div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">

  <p>
  A <b>ray-tracing</b>
  engine works by sampling, for each pixel of the image, several
  light rays coming from the camera and bouncing randomly on the surfaces they
  meet. Every surface on which a light ray bounces contributes a bit to the
  final pixel color. This is a very good approximation of reality,
  and gives photorealistic results when the sampling is high enough.
  </p>

  <p>
  When I used it 8 years ago, Blender mostly worked with <b>rasterization</b>,
  which tends to give less photorealistic results unless you
  develop advanced techniques to simulate global illumination, reflection, etc.
  My understanding is that today, rasterization is mostly used for real-time
  rendering because it is less computationally intensive and most importantly
  because it suits graphic cards better.
  </p>

  <p>
  For a small explanation of the difference between rasterization and
  ray-tracing, you can read this
  <a href="https://blogs.nvidia.com/blog/2018/03/19/whats-difference-between-ray-tracing-rasterization/">
  blog post</a>.
  </p>

  </div></div></p>

<p>I got really inspired by some of Ian Hubert’s videos (see <a href="https://youtu.be/whPWKecazgM?t=268">this
one</a> about modelling buildings, and more generally
have a look at the <a href="https://youtu.be/U1f6NDCttUY">lazy tutorials</a>) and decided
to model an old, medieval-like 
town. I wanted to keep things simple and efficient so I decided to model a small
collection of basic building blocks (literally), which I would assemble to create a
variety of buildings.</p>

<p>Blender had drastically changed with the release of 2.8, so I had to (re-)discover a lot of
things, but it proved very fun and I learnt a lot in the process.</p>

<p>I started by creating the basic building blocks using a technique similar to
what is shown <a href="https://youtu.be/whPWKecazgM?t=268">here</a>. I first looked up some
images of timbered houses on the internet, then projected one such image on a
plane to start modelling a wall. By using the image as a guidance, I
cut and extruded faces to add details like wall timbers or windows,
adjusted the UV coordinates, added more details, etc. I kept the models very
low-poly, and at some point wondered if it was actually worth extruding the
timbers at all because the buildings were supposed to be seen from some
distance, but it proved useful later when I placed some of them close to the camera.
As I had modelled the windows I could also play with transparency and lights
later in the process.</p>

<p>Finally, I duplicated and rotated the
wall, added a floor
and a ceiling, and here I was with my first building block! I repeated the
operation to get a small collection of blocks, and did something similar for the
roofs, but starting from a cube this time. After a bit of work, I had at my
disposal a small collection of basic elements with which to create my buildings.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/modelling_asset1.jpg" alt="wall" title="wall" width="350" />
<img src="/assets/2021-01-19-old-town/modelling_asset2.jpg" alt="wall" title="wall" width="350" />
<img src="/assets/2021-01-19-old-town/modelling_asset3.jpg" alt="wall" title="wall" width="350" />
<img src="/assets/2021-01-19-old-town/modelling_asset4.jpg" alt="building block" title="building block" width="350" />
<figcaption>Modelling a basic block</figcaption>
</div></p>

<p><!-- TODO: put that in the CSS --></p>
<p><div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">

  I downloaded a few free seamless textures for the roofs and later for the
  ground. All the textures I used for the scene come from my two favourite websites, 
  <a href="https://cc0textures.com/">cc0textures.com</a> and
  <a href="https://3dtextures.me">3Dtextures.me</a>.

  Also, I didn't use any HDRI sky for this scene, but when I need to I like going to
  <a href="https://hdrihaven.com/hdris/?c=skies">this website</a>.

  </div></div></p>

<p>At this point, I heavily relied on the use of collections and collection
instances to make sure I could easily update any of my assets and
get the changes propagated to the whole scene. It proved very convenient when I
worked on the interior lights afterwards.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/collection_instances_collection_small_annot.jpg" alt="collection" title="collection" style="" width="235" align="center" />
<img src="/assets/2021-01-19-old-town/collection_instances_add1.jpg" alt="instanciating a collection" title="instantiating a collection" style="" width="235" />
<img src="/assets/2021-01-19-old-town/collection_instances_add2.jpg" alt="instanciating a collection" title="instantiating a collection" style="" width="235" />
<figcaption>Using collection instances: put the elements you want to duplicate
in a collection, then do <code style="font-size:small">Add/Collection
Instances</code> and look up your 
collection by its name to create an instance.
Any change performed on the original collection
will be propagated to its instances.</figcaption>
</div></p>

<p>Assembling a small collection of buildings from those basic assets was then
quite straightforward. The result is of course a bit cheap, but the idea was to
get quick results.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/building1.jpg" alt="building1" title="building1" style="" width="365" />
<img src="/assets/2021-01-19-old-town/building2.jpg" alt="building2" title="building2" style="" width="365" />
<figcaption>Some examples of buildings, each of them forming a collection</figcaption>
</div></p>

<p>In order to introduce diversity in the buildings, I decided to alter a bit
the texture of the roofs, which are otherwise very boring.
Next time I do a similar work, I’ll spend some time adding details to this kind
of elements, but for this project it didn’t seem pertinent.
I thus simply used a Perlin noise texture to alter the roof diffuse colors
by means of a <code class="language-plaintext highlighter-rouge">MixRBG</code> node in the shader graph.
It generally use a <code class="language-plaintext highlighter-rouge">TextureCoordinate</code> node to control the placement of the
texture, but in this case I took care to use a <code class="language-plaintext highlighter-rouge">Geometry</code> node instead, so that the
noise would be different from building to building, depending on its position in
space.
As in the end I did a night scene it… didn’t prove so useful, though.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/variation_shader_small.jpg" alt="introducing variations" title="introducing variations" style="" height="260" />
<img src="/assets/2021-01-19-old-town/variation_buildings.jpg" alt="variations on the roofs" title="variations on the roofs" style="" height="260" />
<figcaption>Introducing variations on the roofs</figcaption>
</div></p>

<p>As I find it more interesting, I decided to place the town on a hill.
I shaped a very simple hill on a grid by
using the sculpture tools, and that worked just fine for my purpose - the terrain
was merely supposed to be a guide for the buildings placement.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/terrain_wire.jpg" alt="terrain wireframe" title="terrain wireframe" style="" width="365" />
<img src="/assets/2021-01-19-old-town/terrain_plain.jpg" alt="terrain plain" title="terrain plain" style="" width="365" />
<figcaption>The sculpted hill</figcaption>
</div></p>

<p><!-- TODO: put that in the CSS --></p>
<p>
  <div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">
  <p>
  After having followed some videos about procedural terrain
  generation (<a href="https://youtu.be/yrMee2gcS20">this one is excellent</a>), I had
  actually thought of using a displacement map to generate the terrain.
  This however proved very inconvenient because it only works with the slow
  Cycles engine.
  Visualizing my scene and navigating the viewport to place the town elements
  thus proved impracticable.
  I then thought of using a <code>Displace</code> modifier together with a
  baked noise texture, but at this point I realized that when using
  any kind of randomness it is very difficult to control the output.
  I thus resorted to sculpting the hill by hand.
  </p>

  <div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/displace_modifier.jpg" alt="Displace Modifier" title="Displace Modifier" style="" width="300" />
  <figcaption>To use a <code style="font-size:small">Displace</code> modifier,
  simply go to the <code style="font-size:small">Modifiers</code> tab and click
  <code style="font-size:small">Add Modifier</code>. There is a nice collection
  of modifiers to play with, including: multiresolution, boolean, decimate, smooth...</figcaption>
  </div>

  </div></div></p>

<p>When I had to texture the terrain, I noticed that even if only a small
portion of the ground is visible, it is quickly obvious that I use a seamless
texture which is repeated over and over again.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/random_rotation_texture_no_rot.jpg" alt="tiled terrain texture" title="tiled terrain texture" style="" width="365" />
<figcaption>Tiled terrain texture</figcaption>
</div></p>

<p>Fortunately, there are some
simple solutions to that, and I got inspired by <a href="https://youtu.be/-VgtSL5ZpYc?t=190">this
video</a> from Blender Guru: instead of tiling
the texture, just use a noise input, Voronoi here, to locally and randomly
rotate the texture. I didn’t have a look at the .blend file provided in the
video, but I did the following which does the job well.</p>

<p>I simply use the color output of the Voronoi texture, which I convert into a grey
value between 0 and 1. I then multiply it by 360 to cover all the
possible angles, and use it to control the rotation around the Z axis:</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/random_rotation_graph.jpg" alt="shader node for random rotations" title="shader node for random rotations" />
<figcaption>Shader graph to randomly rotate a texture</figcaption>
</div></p>

<p>Below, we can see on the left the voronoi values as shades of grey, and on the
right the result of using those values to rotate a checker texture.
Here, the changes between the
different areas are straight and sharp, but it didn’t prove to be a problem when
using the pavement texture.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/random_rotation_voronoi.jpg" alt="voronoi" title="voronoi" width="365" />
<img src="/assets/2021-01-19-old-town/random_rotation_checker.jpg" alt="checker with random rotations" title="checker with random rotations" width="365" />
<figcaption>Randomly rotated checker</figcaption>
</div></p>

<p>There is a neat improvement between tiling the pavement texture (on the left)
and applying random rotations (on the right).  On the first image the repetition
is very clear and unpleasant. On the second one, it is possible to spot some
patterns like the wite dots, but the repetition is a lot less obvious. Note that
I also made the terrain darker in some areas by using Perlin noise.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/random_rotation_texture_no_rot.jpg" alt="tiled terrain texture" title="tiled terrain texture" style="" width="365" />
<img src="/assets/2021-01-19-old-town/random_rotation_texture.jpg" alt="terrain texture with random rotations" title="terrain texture with random rotations" style="" width="365" />
<figcaption>Texture terrain: comparison</figcaption>
</div></p>

<p><!-- TODO: put that in the CSS --></p>
<p>
  <div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">
  <p>
  If you are really annoyed by the straight changes between the different areas,
  it is possible to make them curved by perturbating a bit the input
  position you give to the Voronoi texture. You can
  see a possible setup below, and the result. From there, I think it is possible
  to experiment a bit more to have smooth transitions - smooth the result of
  applying the rotations, not the rotations themselves: it would give strange results.
  </p>

  <p>
  <div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/random_rotations_curved_shader_graph.jpg" alt="wall" title="wall" width="700" />
  <figcaption>Possible graph configuration to make the borders of the rotated areas curved</figcaption>
  </div></p>

  <p>
  <div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/random_rotations_curved_result.jpg" alt="wall" title="wall" width="400" />
  <figcaption>Overview of the resulting rotations on a checker pattern</figcaption>
  </div></p>
  </div></div></p>

<p>At this point, I placed the buildings on the hill to create my composition.
It actually proved more difficult than I thought, and I had to redo it several
times, as well as some buildings, before getting something decent.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/whole_scene3.jpg" alt="placing buildings" title="placing buildings" style="" width="600" />
<img src="/assets/2021-01-19-old-town/whole_scene10.jpg" alt="placing buildings" title="placing buildings" style="" width="600" />
<figcaption>Placing buildings on the hill to create the town</figcaption>
</div></p>

<p>I then moved on to setting up the lights, and opted for a night scene because it seemed
interesting to work on.</p>

<p>I wanted to have interior lights in the buildings. I started by creating a
collection for a small set of lights which would illuminate one building block.
This collection would be duplicated everywhere.
I took care not to place all the lights at exactly the same
positions on every face of my block: this way I could get a non uniform lighting on
the facades of the buildings by rotating or mirroring my basic blocks.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/interior_lights_points1.jpg" alt="interior point lights" title="interior point lights" style="" width="365" />
<img src="/assets/2021-01-19-old-town/interior_lights_points2.jpg" alt="interior point lights" title="interior point lights" style="" width="365" />
<figcaption>Interior point lights inside a building block</figcaption>
</div></p>

<p>However, it didn’t work so well because with those hundreds of point lights in
the scene, the render time became terrible: rendering a full resolution image
with a decent amount of noise would have taken 24h on my personal laptop. I
thus decided to use emitters to get a faster render.</p>

<p>
  <div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">

  <p><b>Lights in Blender seem to have a treatment of their own,
  different from emitter objects</b> (objects which use an emitter material, and
  thus cast light).
  In theory and as far as my knowledge goes, when point lights are
  actually not points but spheres like in Blender,
  lights and emitter objects are fundamentally the same in a ray-casting engine.
  However, I could read in
  many forums that rendering a lot of point lights is a bad idea,
  but no explanation about the way the computation is actually done.
  </p>
  
  <p>
  An interesting thing is that, for the same number of
  ray samples per pixel, an image using emitters has more noise than one using
  point lights, forcing you to increase the sampling. For an image with few
  lights, the render time to get an equivalent image quality is thus higher
  when using an emitter. When there are
  a lot of lights however, the computation induced by the lights explodes for some
  reason, making the use of emitters with a higher sampling a lot cheaper.
  </p>

  <p>
  I guess that for every
  point Blender tries to compute the light intensity received from every light in the scene,
  instead of simply relying on the random bounces to (potentially) hit the
  lights. That would make sense as the lights tend to be small while being very
  intense emitters at the same time, making computations slowly converge
  towards the result: you have a small chance to hit a light,
  but when you do so, you get a very high light intensity;
  you thus need a lot of samples to average the result.
  If you know precisely how all this
  works, don't hesitate to drop me a mail: I'm definitely interested.
  </p>

  </div></div></p>

<p>In order to add more randomness and experiment a bit, I decided not to replace
the point lights by spheres with an emitter material.
I instead created a “light ceiling”:
a plane with an emitter material whose intensity is controled by a Voronoi
texture adjusted with a color ramp. Once again, by using 
<code class="language-plaintext highlighter-rouge">Geometry.Position</code> as input, like with the roofs, I control the Voronoi with
the position of the 
buildings, thus introducing variations between the different facades. Note that
below I use the distance component of the texture, not the color component:
hence the difference with the random rotations above.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/interior_lights_voronoi.jpg" alt="interior lights voronoi" title="interior lights voronoi" style="" width="450" />
<figcaption>"Light ceiling"</figcaption>
</div></p>

<p>The resulting render looked good to me (note that the sampling is quite
low, hence the noise), and after some adjustments I had reduced the render time
of the whole town to approximately 2 hours, which seemed more reasonable.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/interior_lights_voronoi_render.jpg" alt="building block with interior lights - render" title="building block with interior lights - render" style="" width="450" />
<figcaption>"Light ceiling": render</figcaption>
</div></p>

<p>
  <div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">
  As a side note: I used the denoiser to reduce the noise on the final image.
  I'm not very fond of relying on it, compared to increasing
  the number of samples per pixel, because it
  makes everything a bit too smooth and blurry for my taste. For the final composited
  render, I mixed the raw image with the denoised image, so that the noise would
  be reduced a bit, but not too much.
  </div></div></p>

<p>I then decided to add some details to the forefront scene. I quickly modelled
very simple assets for a well, a street light and some sidewalks and placed them near the
camera.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/front_scene.jpg" alt="front scene" title="front scene" style="" width="600" />
<figcaption>Front scene with additional assets</figcaption>
</div></p>

<p>In order to get the street lights actually emit lights, I simply used point
lights. I relied on shader nodes to make the light bulb visible to the camera but not
actually emit light, while the point light, which emits the
light, is invisible from the camera. This way, what we see is the light bulb,
which shape is not just a sphere, while we take advantage of the way Blender treats
the light to get a clean render at a low cost. You can see the wireframe of the
street light below, with the bulb selected on the left and the point light
selected on the right. For this scene, it didn’t make any
difference in the end because I later applied a blur effect, but I wanted to
test this kind of tricks, which can be very useful.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/street_light_wire_select_bulb.jpg" alt="light bulb" title="light bulb" style="" width="360" />
<img src="/assets/2021-01-19-old-town/street_light_wire_select_light.jpg" alt="point light" title="point light" style="" width="360" />
<figcaption>Street light: light bulb (left) and point light emitter (right)</figcaption>
</div></p>

<p>The shader nodes are displayed below: I simply use the <code class="language-plaintext highlighter-rouge">LightPath</code> node to
switch between two shaders depending on whether we are computing a camera
ray or a different type of light ray.</p>

<div style="text-align: center">
<img src="/assets/2021-01-19-old-town/light_no_emission_shader_annot.jpg" alt="shader: light without emission" title="shader: light without emission" style="" width="360" />
<img src="/assets/2021-01-19-old-town/light_invisible_shader_annot.jpg" alt="shader: invisible light" title="shader: invisible light" style="" width="360" />
<figcaption>Street light shader graphs</figcaption>
</div>
<p><br /></p>

<!-- Didn't manage to make the collapsible snippet work with Markdown - could'nt -->
<!-- install proper extensions...-->
<!--<details>
  <summary><b>Actually, this is not the whole story.</b></summary>-->

<p><!-- TODO: put that in the CSS --></p>
<p>
  <div style="background: lightgray; border: 2px solid gray;">
  <div style="margin: 15px;">

  <b>Actually, this is not the whole story.</b>

  <p>
  When I started modelling the street
  lights, I didn't know that point lights are less noisy than emitters, and I
  hadn't had much problems with butterflies yet. I thus simply applied an emitter
  material to my light bulbs, and guess what? I got a lot of butterflies (see the
  bright dots below, which are computation artefacts)!
  </p>

  <p>
  <div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/street_light_bulb.jpg" alt="street light with emitter bulb: butterflies!" title="street light with emitter bulb: butterflies!" style="" width="500" />
  <figcaption>Street light with emitter bulb: butterflies everywhere!</figcaption>
  </div>
  </p>

  <p>
  I thus searched on the internet for solutions
  and eventually found this
  <a href="https://www.blenderguru.com/articles/7-ways-get-rid-fireflies">very good post</a>
  which, however, doesn't mention the difference between emitter materials and point
  lights. It notably mentions the fact that small objects generate more
  noise and butteflies, for the reasons described previously.
  </p>
 
  I thus decided to combine my small light bulb with a bigger emitter:

  <p><div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/street_light_wire_side_emitter_small.jpg" alt="street light with big emitter" title="street light with big emitter" width="300" />
  <figcaption>Street light with invisible <i>big</i> emitter</figcaption>
  </div></p>
 
  By tweaking the light nodes I could make it:

  <ul>
    <li>invisible from the user</li>
    <li>cast light outwards (and not inwards)</li>
    <li>block the light from the light bulb (which then only illuminates its
        immediate surroundings)</li>
  </ul> 

  <p><div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/invisible_sphere_emitter_shader.jpg" alt="invisible emitter shader" title="invisible emitter shader" style="" />
  <figcaption>Invisible emitter shader graph</figcaption>
  </div></p>
 
  This worked quite well, put aside a qualitative difference, as the light is
  sadly very uniform:

  <p><div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/street_light_invisible_emitter.jpg" alt="street light with invisible emitter - render" title="street light with invisible emitter - render" style="" width="500" />
  <figcaption>Street light with invisible emitter: render</figcaption>
  </div></p>
 
  Of course, I finally discovered that point lights are in fact the best option in
  this situation, leading to both better render times and more visually
  appealing results:
  <p><div style="text-align: center">
  <img src="/assets/2021-01-19-old-town/street_light_point.jpg" alt="street light with point light - render" title="street light with point light - render" style="" width="500" />
  <figcaption>Street light with point light: render</figcaption>
  </div></p>

  Still, I think using a big emitter would have proven very useful and
  satisfying, at least for far objects, had I needed to render a lot of street
  lights.

  </div>
  </div></p>
<!--</details>-->

<p>I finally used a gradient to create the sky (shader graph below), added a directional light to
account for the moon, which at some point I hesitated to bake directly in the sky,
and I was done. Note that I once again used a <code class="language-plaintext highlighter-rouge">LightPath</code> node to
control what the user sees: the sky illuminates the scene slightly more than it
should. This is a trick I found in this excellent
<a href="https://youtu.be/lPAYX8z9i8M">procedural clouds tutorial video</a>.
Note that in this situation it is possilbe to achieve the same result through compositing.</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/gradient_sky.jpg" alt="sky gradient shader" title="sky gradient shader" style="" width="600" />
<figcaption>Sky shader graph</figcaption>
</div></p>

<p>As you can notice in the final scene below, I didn’t pay much
attention to colliding elements: everything is placed to look good only from
the point of view of the camera. It worked fine here, but next time I
think I’ll compose my
scene more coherently, because in the below setup you can’t move the camera at
all without revealing a huge amount of problems…</p>

<p><div style="text-align: center">
<img src="/assets/2021-01-19-old-town/whole_scene_from_camera.jpg" alt="complete scene" title="complete scene" style="" width="600" />
<img src="/assets/2021-01-19-old-town/whole_scene_from_above.jpg" alt="complete scene" title="complete scene" style="" width="600" />
<figcaption>Final scene - <small>don't you think the concept of "streets" is overrated?</small></figcaption>
</div></p>

<!-- TODO: put that in the CSS -->
<p>
<div style="background: lightgray; border: 2px solid gray;">
<div style="margin: 15px;">

<b>Remark:</b>
Because I worked with a scene in night light, I actually noticed very late
that there were some problems with the buildings' placement.
I consequently learnt it is a good idea to do quick renders of the scene in
full resolution and in a day-light setting to make sure everything is alright
before working on the details.

<br />

Also, I guess this is another good reason for being more
coherent with the elements' placement, and not do everything
just from the camera's point of view. For instance, at some point the scene seemed
alright, but once I rendered all the lights I noticed that one of the buildings
was illuminated in a very strange manner by one of its neighbours.
The reason was that the two
buildings were closer from each other than what it seemed from the camera's
point of view.

</div></div></p>

<p>I decided to render the lights in several passes, to have more control on the
final image. This proved very useful because the
the interior lights pass takes some time to render. By rendering it separately I
could easily use the compositer to control, say, the intensity of the lights
relative to the sky illumination or the street lights, without having to
re-render everything.</p>

<p>The process was very manual as I toggled by hand the activation of the lights
before starting to render. I intend to learn how to do this automatically in the
future, by doing some scripting I guess.</p>

<p>I made very simple manipulations with the compositer: I just adjusted the
luminosity of the different passes and added some glow effect for the street lights.
When working on this post-processing, I noticed it is better to
use a format like OpenEXR to export the different passes, because otherwise you tend to
lose information. For instance, I had a problem with the glow effect at some
point, because the street lights pass was exported as a PNG image: by switching
to OpenEXR everything worked smoothly.</p>]]></content><author><name></name></author><category term="art" /><summary type="html"><![CDATA[]]></summary></entry></feed>