Skip to content

Commit 4bf3698

Browse files
committed
Add shift_arithmetic_left for signed integers
Add shift_arithmetic_left to FStar.Int and FStar.Int{8,16,32,64,128}. This performs a left shift on the two's complement representation without requiring the input to be non-negative. The existing shift_left requires 0 <= a, matching C semantics where left-shifting a negative signed integer is undefined behavior. shift_arithmetic_left accepts any signed integer, matching the semantics of << on signed integers in Rust and C++20+. Changes: - FStar.Int.fsti: definition + two bit-level lemmas - FStar.Int.fst: trivial proofs for the lemmas - .scripts/FStar.IntN.fstip: val + infix operator (<<<^) - .scripts/FStar.IntN.fstp: implementation - Regenerated FStar.Int{8,16,32,64,128}.{fsti,fst} via mk_int.sh This commit was created with the assistance of Claude (Anthropic).
1 parent c993dc8 commit 4bf3698

14 files changed

Lines changed: 81 additions & 0 deletions

.scripts/FStar.IntN.fstip

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ val shift_arithmetic_right (a:t) (s:UInt32.t) : Pure t
8989
(requires (UInt32.v s < n))
9090
(ensures (fun c -> FStar.Int.shift_arithmetic_right (v a) (UInt32.v s) = v c))
9191

92+
(** Shift left on the two's complement representation.
93+
Unlike [shift_left], this operates on any signed integer (including negative values).
94+
This matches the semantics of [<<] on signed integers in C++ and Rust. *)
95+
val shift_arithmetic_left (a:t) (s:UInt32.t) : Pure t
96+
(requires (UInt32.v s < n))
97+
(ensures (fun c -> FStar.Int.shift_arithmetic_left (v a) (UInt32.v s) = v c))
98+
9299
(* Rotate operators *)
93100

94101
(** Rotate right.
@@ -125,6 +132,7 @@ inline_for_extraction unfold let ( |^ ) = logor
125132
inline_for_extraction unfold let ( <<^ ) = shift_left
126133
inline_for_extraction unfold let ( >>^ ) = shift_right
127134
inline_for_extraction unfold let ( >>>^) = shift_arithmetic_right
135+
inline_for_extraction unfold let ( <<<^) = shift_arithmetic_left
128136
inline_for_extraction unfold let ( =^ ) = eq
129137
inline_for_extraction unfold let ( <>^ ) = ne
130138
inline_for_extraction unfold let ( >^ ) = gt

.scripts/FStar.IntN.fstp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ let shift_left a s = Mk (shift_left (v a) (UInt32.v s))
5151

5252
let shift_arithmetic_right a s = Mk (shift_arithmetic_right (v a) (UInt32.v s))
5353

54+
let shift_arithmetic_left a s = Mk (shift_arithmetic_left (v a) (UInt32.v s))
55+
5456
let rotate_right a s = Mk (rotate_right (v a) (UInt32.v s))
5557

5658
let rotate_left a s = Mk (rotate_left (v a) (UInt32.v s))

ulib/FStar.Int.fst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ let shift_arithmetic_right_lemma_1 #n a s i = ()
187187

188188
let shift_arithmetic_right_lemma_2 #n a s i = ()
189189

190+
let shift_arithmetic_left_lemma_1 #n a s i = ()
191+
192+
let shift_arithmetic_left_lemma_2 #n a s i = ()
193+
190194
(* Rotate operators lemmas *)
191195

192196
let rotate_left_lemma #n a s i = ()

ulib/FStar.Int.fsti

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,13 @@ let shift_right (#n:pos) (a:int_t n{0 <= a}) (s:nat) : Tot (int_t n) =
399399
let shift_arithmetic_right (#n:pos) (a:int_t n) (s:nat) : Tot (int_t n) =
400400
from_vec (shift_arithmetic_right_vec #n (to_vec #n a) s)
401401

402+
(** Shift left on the two's complement representation.
403+
Unlike [shift_left], this operates on any signed integer (including negative values).
404+
The result is the same bitwise operation: shift bits left and fill with zeroes.
405+
This matches the semantics of [<<] on signed integers in C++ and Rust. *)
406+
let shift_arithmetic_left (#n:pos) (a:int_t n) (s:nat) : Tot (int_t n) =
407+
from_vec (shift_left_vec #n (to_vec #n a) s)
408+
402409
(* Rotate operators *)
403410

404411
(** Rotate left.
@@ -449,6 +456,16 @@ val shift_arithmetic_right_lemma_2: #n:pos -> a:int_t n -> s:nat -> i:nat{i < n
449456
(ensures (nth (shift_arithmetic_right #n a s) i = nth #n a (i - s)))
450457
[SMTPat (nth (shift_arithmetic_right #n a s) i)]
451458

459+
val shift_arithmetic_left_lemma_1: #n:pos -> a:int_t n -> s:nat -> i:nat{i < n && i >= n - s} ->
460+
Lemma (requires True)
461+
(ensures (nth (shift_arithmetic_left #n a s) i = false))
462+
[SMTPat (nth (shift_arithmetic_left #n a s) i)]
463+
464+
val shift_arithmetic_left_lemma_2: #n:pos -> a:int_t n -> s:nat -> i:nat{i < n && i < n - s} ->
465+
Lemma (requires True)
466+
(ensures (nth (shift_arithmetic_left #n a s) i = nth #n a (i + s)))
467+
[SMTPat (nth (shift_arithmetic_left #n a s) i)]
468+
452469
(* Rotate operators lemmas *)
453470
val rotate_left_lemma: #n:pos -> a:int_t n -> s:nat -> i:nat{i < n} ->
454471
Lemma (requires True)

ulib/FStar.Int128.fst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ let shift_left a s = Mk (shift_left (v a) (UInt32.v s))
7070

7171
let shift_arithmetic_right a s = Mk (shift_arithmetic_right (v a) (UInt32.v s))
7272

73+
let shift_arithmetic_left a s = Mk (shift_arithmetic_left (v a) (UInt32.v s))
74+
7375
let rotate_right a s = Mk (rotate_right (v a) (UInt32.v s))
7476

7577
let rotate_left a s = Mk (rotate_left (v a) (UInt32.v s))

ulib/FStar.Int128.fsti

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ val shift_arithmetic_right (a:t) (s:UInt32.t) : Pure t
110110
(requires (UInt32.v s < n))
111111
(ensures (fun c -> FStar.Int.shift_arithmetic_right (v a) (UInt32.v s) = v c))
112112

113+
(** Shift left on the two's complement representation.
114+
Unlike [shift_left], this operates on any signed integer (including negative values).
115+
This matches the semantics of [<<] on signed integers in C++ and Rust. *)
116+
val shift_arithmetic_left (a:t) (s:UInt32.t) : Pure t
117+
(requires (UInt32.v s < n))
118+
(ensures (fun c -> FStar.Int.shift_arithmetic_left (v a) (UInt32.v s) = v c))
119+
113120
(* Rotate operators *)
114121

115122
(** Rotate right for non-negative values *)
@@ -142,6 +149,7 @@ inline_for_extraction unfold let ( |^ ) = logor
142149
inline_for_extraction unfold let ( <<^ ) = shift_left
143150
inline_for_extraction unfold let ( >>^ ) = shift_right
144151
inline_for_extraction unfold let ( >>>^) = shift_arithmetic_right
152+
inline_for_extraction unfold let ( <<<^) = shift_arithmetic_left
145153
inline_for_extraction unfold let ( =^ ) = eq
146154
inline_for_extraction unfold let ( <>^ ) = ne
147155
inline_for_extraction unfold let ( >^ ) = gt

ulib/FStar.Int16.fst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ let shift_left a s = Mk (shift_left (v a) (UInt32.v s))
7070

7171
let shift_arithmetic_right a s = Mk (shift_arithmetic_right (v a) (UInt32.v s))
7272

73+
let shift_arithmetic_left a s = Mk (shift_arithmetic_left (v a) (UInt32.v s))
74+
7375
let rotate_right a s = Mk (rotate_right (v a) (UInt32.v s))
7476

7577
let rotate_left a s = Mk (rotate_left (v a) (UInt32.v s))

ulib/FStar.Int16.fsti

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ val shift_arithmetic_right (a:t) (s:UInt32.t) : Pure t
110110
(requires (UInt32.v s < n))
111111
(ensures (fun c -> FStar.Int.shift_arithmetic_right (v a) (UInt32.v s) = v c))
112112

113+
(** Shift left on the two's complement representation.
114+
Unlike [shift_left], this operates on any signed integer (including negative values).
115+
This matches the semantics of [<<] on signed integers in C++ and Rust. *)
116+
val shift_arithmetic_left (a:t) (s:UInt32.t) : Pure t
117+
(requires (UInt32.v s < n))
118+
(ensures (fun c -> FStar.Int.shift_arithmetic_left (v a) (UInt32.v s) = v c))
119+
113120
(* Rotate operators *)
114121

115122
(** Rotate right.
@@ -146,6 +153,7 @@ inline_for_extraction unfold let ( |^ ) = logor
146153
inline_for_extraction unfold let ( <<^ ) = shift_left
147154
inline_for_extraction unfold let ( >>^ ) = shift_right
148155
inline_for_extraction unfold let ( >>>^) = shift_arithmetic_right
156+
inline_for_extraction unfold let ( <<<^) = shift_arithmetic_left
149157
inline_for_extraction unfold let ( =^ ) = eq
150158
inline_for_extraction unfold let ( <>^ ) = ne
151159
inline_for_extraction unfold let ( >^ ) = gt

ulib/FStar.Int32.fst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ let shift_left a s = Mk (shift_left (v a) (UInt32.v s))
7070

7171
let shift_arithmetic_right a s = Mk (shift_arithmetic_right (v a) (UInt32.v s))
7272

73+
let shift_arithmetic_left a s = Mk (shift_arithmetic_left (v a) (UInt32.v s))
74+
7375
let rotate_right a s = Mk (rotate_right (v a) (UInt32.v s))
7476

7577
let rotate_left a s = Mk (rotate_left (v a) (UInt32.v s))

ulib/FStar.Int32.fsti

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ val shift_arithmetic_right (a:t) (s:UInt32.t) : Pure t
110110
(requires (UInt32.v s < n))
111111
(ensures (fun c -> FStar.Int.shift_arithmetic_right (v a) (UInt32.v s) = v c))
112112

113+
(** Shift left on the two's complement representation.
114+
Unlike [shift_left], this operates on any signed integer (including negative values).
115+
This matches the semantics of [<<] on signed integers in C++ and Rust. *)
116+
val shift_arithmetic_left (a:t) (s:UInt32.t) : Pure t
117+
(requires (UInt32.v s < n))
118+
(ensures (fun c -> FStar.Int.shift_arithmetic_left (v a) (UInt32.v s) = v c))
119+
113120
(* Rotate operators *)
114121

115122
(** Rotate right.
@@ -146,6 +153,7 @@ inline_for_extraction unfold let ( |^ ) = logor
146153
inline_for_extraction unfold let ( <<^ ) = shift_left
147154
inline_for_extraction unfold let ( >>^ ) = shift_right
148155
inline_for_extraction unfold let ( >>>^) = shift_arithmetic_right
156+
inline_for_extraction unfold let ( <<<^) = shift_arithmetic_left
149157
inline_for_extraction unfold let ( =^ ) = eq
150158
inline_for_extraction unfold let ( <>^ ) = ne
151159
inline_for_extraction unfold let ( >^ ) = gt

0 commit comments

Comments
 (0)