5
5
6
6
## rust-lean-models
7
7
8
- Lean models of various Rust libraries to facilitate Lean-based verification of Rust programs.
8
+ Lean models of various functions and data types from Rust libraries to facilitate Lean-based verification of Rust programs.
9
9
10
10
11
11
## Description
12
- The library defines equivalent Lean versions of functions from the Rust standard library.
13
- This library is intended to be used for verifying Rust programs via Lean.
12
+ This library is intended to be used for verifying Rust programs via Lean. It
13
+ defines equivalent Lean versions of functions from the Rust standard library.
14
+
15
+ The Lean definitions are based on the description of the Rust functions, which is published at https://doc.rust-lang.org/std .
14
16
15
- The Lean implementation is based on the description of the Rust functions, which are published at https://doc.rust-lang.org/std .
16
17
The library includes:
17
- - Definitions of functions equivalent to those from the Rust standard library
18
+ - Definitions of Lean functions equivalent to those from the Rust standard library
18
19
- Proofs that these definitions are consistent with the description of the Rust functions
19
20
- Supporting lemmas and theorems for proof construction
20
21
@@ -42,40 +43,48 @@ The library includes:
42
43
## Usage
43
44
### Translating a Rust program
44
45
45
- For any Rust built-in functions which are used in user code, map it with
46
- the corresponding function name in the library (see the Tables below).
46
+ Replace the Rust built-in functions that are used in your code with the
47
+ corresponding Lean function in this library.
48
+
49
+ Tables in [ RustString.md] ( RustLeanModels/RustString.md )
50
+ and [ Iterators.md] ( RustLeanModels/Iterator.md ) give the mapping from Rust types
51
+ and functions to their Lean equivalents.
47
52
48
53
### Proof Tutorial
54
+
49
55
We demonstrate the applications of the library and some proof techniques
50
- for String programs in
51
- [ ProofTutorial.lean] ( https://github.com/model-checking/rust-lean-models/tree/main/RustLeanModels/ProofTutorial.lean )
52
- through two simple programs that compute the longest common prefix
53
- and longest common substring of the two input strings.
56
+ for string programs in
57
+ [ ProofTutorial.lean] ( https://github.com/model-checking/rust-lean-models/tree/main/RustLeanModels/ProofTutorial.lean ) .
58
+ This tutorial shows the correctness of two simple programs that compute the longest common prefix
59
+ and longest common substring of the two strings.
54
60
More examples can be found in
55
61
[ ProofExample.lean] ( https://github.com/model-checking/rust-lean-models/tree/main/RustLeanModels/ProofExample.lean ) .
56
62
57
- ## Implementation
63
+ ## Details
58
64
65
+ ### Recursive function definitions
59
66
60
- ### Recursive function definition
61
67
For each Rust function, we provide a recursive Lean function. Implementing
62
- the equivalent functions in Lean recursively enables user to construct
68
+ the equivalent functions in Lean recursively enables users to construct
63
69
induction proofs conveniently. The Lean function has the same name as the Rust original,
64
- except when the Rust name clashes with a Lean keyword. In case of a clash, a Rust function ' func_name'
70
+ except when the Rust name clashes with a Lean keyword. In case of a clash, a Rust function ` func_name `
65
71
is renamed to ` rust_func_name ` in Lean.
66
72
67
73
Implementing a function recursively may requires some extra parameters.
68
- In those cases, first, we implement an auxiliary function (name: ` func_name_aux ` ) which is defined
69
- recursively with the parameters, then we define the function ` func_name ` based on the auxiliary function
70
- with initial values for the parameters.
74
+ In those cases, we first define an auxiliary function (name: ` func_name_aux ` ) which is defined
75
+ recursively with the extra parameters, then we define the function ` func_name ` based on the auxiliary function
76
+ with initial values for the parameters.
71
77
For example, ` char_indices ` is defined based on ` char_indices_aux ` as
72
- ` def char_indices (s: Str) := char_indices_aux s 0 ` .
78
+ ``` lean
79
+ def char_indices (s: Str) := char_indices_aux s 0
80
+ ```
73
81
74
- For Rust functions involving the ` Pattern ` type, we implement two recursive sub-functions
75
- (name: ` func_name_char_filter ` and ` func_name_substring ` ) which replace the ` Pattern ` type
76
- in the input by either a char filter (or type` Char → Bool ` ) or a ` List Char ` . Then we define
77
- the function ` func_name ` based on these two sub-functions by matching the input of ` Pattern ` type.
78
- For example, ` split ` is defined by two sub-functions ` split_char_filter ` and ` split_substring ` as:
82
+ For Rust functions that use the Rust ` Pattern ` type, we implement two recursive sub-functions
83
+ (name: ` func_name_char_filter ` and ` func_name_substring ` ) that replace the ` Pattern ` type
84
+ in the input with either a char filter (of type` Char → Bool ` ) or a string (of type ` List Char ` ).
85
+ Then we define the function ` func_name ` based on these two sub-functions by matching the
86
+ input of ` Pattern ` type. For example, ` split ` is defined by two sub-functions
87
+ ` split_char_filter ` and ` split_substring ` as:
79
88
80
89
``` lean
81
90
def split (s: Str) (p: Pattern) := match p with
@@ -84,7 +93,8 @@ def split (s: Str) (p: Pattern) := match p with
84
93
| Pattern.FilterFunction f => split_char_filter s f
85
94
| Pattern.WholeString s1 => split_substring s s1
86
95
```
87
- All recursive implementations are proven to be "correct" in the sense that
96
+
97
+ All recursive implementations are proven to be "correct" in the sense that
88
98
they are consistent with the descriptions of the Rust versions (see below for more details).
89
99
90
100
## Correctness Proofs
@@ -118,7 +128,6 @@ In some cases, constructing a non-induction proof using the definitional version
118
128
if i < Char.utf8Size h then false else is_char_boundary t (i - Char.utf8Size h)
119
129
```
120
130
121
-
122
131
and an equivalence theorem
123
132
124
133
```lean
@@ -128,7 +137,7 @@ In some cases, constructing a non-induction proof using the definitional version
128
137
When the description of a Rust function cannot be efficiently expressed in Lean (requires recursions, or is unintuitive),
129
138
we can:
130
139
- Define the definitional version (similar to Case 1) based on a recursive trivial function, then prove the equivalence theorem.
131
- For example, the `byteSize_def` function is defined on the simple function `sum_list_Nat`
140
+ For example, the `byteSize_def` function is based on the function `sum_list_Nat`
132
141
that computes the sum of a list of natural numbers:
133
142
134
143
```lean
@@ -138,20 +147,23 @@ that computes the sum of a list of natural numbers:
138
147
139
148
- Define and prove the correctness of one/some subordinate function(s),
140
149
then define the definitional version based on them.
141
- For example, to define `split_inclusive_char_filter_def`, firstly we define and prove the coreectness of two functions:
150
+ For example, to define `split_inclusive_char_filter_def`, we first define and prove the correctness of two functions:
142
151
- `list_char_filter_charIndex (s: Str) (f: Char → Bool)`: returns the list of positions of characters in `s` satisfying the filter `f`
143
152
144
- - `split_at_charIndex_list (s: Str) (l: List Nat)`: split the strings `s` at positions in `l`
153
+ - `split_at_charIndex_list (s: Str) (l: List Nat)`: splits the strings `s` at positions in `l`
145
154
146
- then define `split_inclusive_char_filter_def` based on them :
155
+ then we define `split_inclusive_char_filter_def` as follows :
147
156
148
157
```lean
149
- def split_inclusive_char_filter_def (s: Str) (f: Char → Bool):= split_at_charIndex_list s (List.map (fun x => x+1) (list_char_filter_charIndex s f))
158
+ def split_inclusive_char_filter_def (s: Str) (f: Char → Bool) :=
159
+ split_at_charIndex_list s (List.map (fun x => x+1) (list_char_filter_charIndex s f))
150
160
```
151
161
152
- ### When the Rust documentation describes properties of the return value
162
+ ### When the Rust documentation describes properties of the return value
163
+
153
164
We state and prove a soundness theorem for the function with
154
165
name: `func_name_sound` and type: `x = func_name input1 input2 ... ↔ properties of x`.
166
+
155
167
For example, the soundness theorem for the function `floor_char_boundary` defined as:
156
168
157
169
```lean
@@ -174,16 +186,17 @@ theorem floor_char_boundary_sound: flp = floor_char_boundary s p
174
186
- The modus ponens (→) direction of the theorem is enough to ensure the correctness of the recursive version
175
187
if the properties in the right-hand-side ensure that the function in the left-hand-side is deterministic.
176
188
- The modus ponens reverse (←) direction ensures that we stated enough properties in right-hand-side such that
177
- it can be satisfied by only one function.
178
- - If the function returns an option, we separately state and prove two soundness theorems for the two cases
189
+ it can be satisfied by only one function.
190
+
191
+ If the function returns an option, we separately state and prove two soundness theorems for the two cases
179
192
of the return value: ` func_name_none_sound ` and ` func_name_some_sound ` . For example:
180
193
181
194
```lean
182
195
theorem split_at_none_sound : split_at s p = none ↔ ¬ ∃ s1, List.IsPrefix s1 s ∧ byteSize s1 = p
183
196
theorem split_at_some_sound : split_at s p = some (s1, s2) ↔ byteSize s1 = p ∧ s = s1 ++ s2
184
197
```
185
198
186
- - For functions involving the ` Pattern ` type, we separately state and prove two equivalent/soundness
199
+ For functions involving the ` Pattern ` type, we separately state and prove two equivalent/soundness
187
200
theorems for the two sub-functions discussed previously (` func_name_char_filter_EQ ` and ` func_name_substring_EQ ` )
188
201
or (` func_name_char_filter_sound ` and ` func_name_substring_sound ` ). For example:
189
202
0 commit comments