Why3 Standard Library index


Program functions on bitvectors with preconditions

This module provides extra functions with pre-conditions ensuring the absence of overflows.

Those pre-conditions are expressed in term of interpretation into mathematical integers, or using bitvectors of size 128.

Generic module, for a parametric size

module BVCheck_Gen
  use int.Int

  type t

  constant size : int
  constant bv_size : t

  (* Overflow checks are performed using bitvectors of size 128. Thus
     this module cannot be cloned with a [size] > 64. *)
  axiom not_greater_than_64 : size <= 64

  constant two_power_size : int
  constant two_power_size_minus_one : int
  constant zeros           : t
  constant minus_one : t

  function to_uint t   : int
  function to_int t   : int
  function of_int  int : t

  function add  t t : t
  function sub  t t : t
  function mul  t t : t
  function udiv t t : t
  function urem t t : t
  function sdiv t t : t
  function srem t t : t

  function lsl    t int : t
  function lsl_bv t t   : t
  function lsr    t int : t
  function lsr_bv t t   : t
  function asr    t int : t
  function asr_bv t t   : t

  predicate ule t t
  predicate ult t t
  predicate uge t t
  predicate ugt t t

  predicate sle t t
  predicate slt t t
  predicate sge t t
  predicate sgt t t

  use bv.BV128 as BV128

  function sto_bv128 t : BV128.t
  function uto_bv128 t : BV128.t

  constant min_sint : t
  constant max_sint : t
  constant max_uint : t
  constant min_sint_as_bv128 : BV128.t = sto_bv128 min_sint
  constant max_sint_as_bv128 : BV128.t = sto_bv128 max_sint
  constant max_uint_as_bv128 : BV128.t = uto_bv128 max_uint

  val u_add (a b:t) : t
    requires { [@expl:arithmetic overflow]
                  to_uint a + to_uint b < two_power_size
               \/ BV128.ule (BV128.add (uto_bv128 a) (uto_bv128 b)) max_uint_as_bv128 }
    ensures  { to_uint result = to_uint a + to_uint b }
    ensures  { result = add a b }

unsigned addition forbidding overflows

  val s_add (a b:t) : t
    requires { [@expl:arithmetic overflow]
      - two_power_size_minus_one <= to_int a + to_int b < two_power_size_minus_one
      \/ let r = BV128.add (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { to_int result = to_int a + to_int b }
    ensures  { result = add a b }

signed addition forbidding overflows

  val u_sub (a b:t) : t
    requires { [@expl:arithmetic overflow] to_uint a >= to_uint b \/ uge a b }
    ensures  { result = sub a b }
    ensures  { to_uint result = to_uint a - to_uint b }

unsigned subtraction with overflow check

  val s_sub (a b:t) : t
    requires { [@expl:arithmetic overflow]
      - two_power_size_minus_one <= to_int a - to_int b < two_power_size_minus_one
      \/ let r = BV128.sub (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { result = sub a b }
    ensures  { to_int result = to_int a - to_int b }

signed subtraction with overflow check

  val u_mul (a b:t) : t
    requires { [@expl:arithmetic overflow]
                  to_uint a * to_uint b < two_power_size
               \/ BV128.ule (BV128.mul (uto_bv128 a) (uto_bv128 b)) max_uint_as_bv128 }
    ensures  { result = mul a b }
    ensures  { to_int result = to_uint a * to_uint b }

unsigned multiplication with overflow check

  val s_mul (a b:t) : t
    requires { [@expl:arithmetic overflow]
      - two_power_size_minus_one <= to_int a * to_int b < two_power_size_minus_one
      \/ let r = BV128.mul (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { result = mul a b }
    ensures  { to_int result = to_int a * to_int b }

signed multiplication with overflow check

  use bv.Pow2int

  val u_lsl (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b bv_size \/ to_uint b < size }
    ensures  { result = lsl_bv a b }
    ensures  { result = lsl a (to_uint b) }

A logical shift left requiring the second argument to be smaller than bitvector size. For this function we do not forbid overflow: bits can be lost'' on the left. This function corresponds to the left shifting [<<] of unsigned ints in C or Java

  val s_lsl (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b bv_size \/ to_uint b < size }
    requires { [@expl:out-of-bounds shifting]
                sle zeros a \/ to_int a >= 0 }
    requires { [@expl:arithmetic overflow]
      (to_int a) * (pow2 (to_int b)) < two_power_size_minus_one
      \/ let r = BV128.lsl_bv (sto_bv128 a) (sto_bv128 b) in
         (BV128.sle min_sint_as_bv128 r /\ BV128.sle r max_sint_as_bv128) }
    ensures  { result = lsl_bv a b }
    ensures  { result = lsl a (to_uint b) }

Alternative logical shift left, still requiring the second argument to be smaller than bitvector size, but also forbidding overflow. This function corresponds to the left shifting [<<] of signed ints in C or Java

  val u_lsr (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b bv_size \/ to_uint b < size }
    ensures  { result = lsr_bv a b }
    ensures  { result = lsr a (to_uint b) }

Logical shift right, requiring the second argument to be smaller than bitvector size. No overflow can occur anyway. This function corresponds to the (logical) right shifting [>>] of unsigned ints in C or Java.

  val s_asr (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b bv_size \/ to_uint b < size }
    ensures  { result = asr_bv a b }
    ensures  { result = asr a (to_uint b) }

The so-called "arithmetic" shift right, requirings the second argument to be smaller than bitvector size. This function corresponds to the arithmetic right shifting [>>>] of signed ints in Java, that does not exist in C.

  val s_asr_strict (a b:t) : t
    requires { [@expl:out-of-bounds shifting]
                ult b bv_size \/ to_uint b < size }
    requires { [@expl:out-of-bounds shifting]
                sge a zeros \/ to_int a >= 0 }
    ensures  { result = asr_bv a b }
    ensures  { result = asr a (to_uint b) }

The shift right function for signed int, requirings the second argument to be smaller than bitvector size, and that the first argument in non-negative. This function corresponds to the right shifting [>>] of signed ints in C.

  use int.EuclideanDivision as ED

  val u_div (a b:t) : t
    requires { [@expl:division by zero] b <> zeros \/ to_uint b <> 0 }
    ensures  { to_uint result = ED.div (to_uint a) (to_uint b) }
    ensures  { result = udiv a b }

unsigned division requires the second argument to be non-zero

  val u_rem (a b:t) : t
    requires { [@expl:remainder by zero] b <> zeros  \/ to_uint b <> 0 }
    ensures  { to_uint result = ED.mod (to_uint a) (to_uint b) }
    ensures  { result = urem a b }

unsigned remainder requires the second argument to be non-zero

  use int.ComputerDivision as CD

  val s_div (a b:t) : t
    requires { [@expl:division by zero] b <> zeros  \/ to_int b <> 0 }
    requires { [@expl:signed division overflow check] (a <> min_sint \/ b <> minus_one)
                \/ (to_int a <> to_int min_sint \/ to_int b <> -1)}
    ensures  { to_int result = CD.div (to_int a) (to_int b) }
    ensures  { result = sdiv a b }

signed division requires the second argument to be non-zero, but also that either the dividend is not [min_int] or the divisor is not [-1]

  val s_rem (a b:t) : t
    requires { [@expl:remainder by zero] b <> zeros \/ to_int b <> 0 }
    ensures  { to_int result = CD.mod (to_int a) (to_int b) }
    ensures  { result = srem a b }

signed remainder requires the second argument to be non-zero

  val us_eq (a b:t) : bool
    ensures { result <-> a = b }

comparison operators have no preconditions

  val us_ne (a b:t) : bool
    ensures { result <-> a <> b }

  val u_le (a b:t) : bool
    ensures { result <-> to_uint a <= to_uint b }
    ensures { result <-> ule a b }

  val u_lt (a b:t) : bool
    ensures { result <-> to_uint a < to_uint b }
    ensures { result <-> ult a b }

  val u_ge (a b:t) : bool
    ensures { result <-> to_uint a >= to_uint b }
    ensures { result <-> uge a b }

  val u_gt (a b:t) : bool
    ensures { result <-> to_uint a > to_uint b }
    ensures { result <-> ugt a b }

  val s_le (a b:t) : bool
    ensures { result <-> to_int a <= to_int b }
    ensures { result <-> sle a b }

  val s_lt (a b:t) : bool
    ensures { result <-> to_int a < to_int b }
    ensures { result <-> slt a b }

  val s_ge (a b:t) : bool
    ensures { result <-> to_int a >= to_int b }
    ensures { result <-> sge a b }

  val s_gt (a b:t) : bool
    ensures { result <-> to_int a > to_int b }
    ensures { result <-> sgt a b }

end

Modules for specific sizes

obtained by cloning the previous generic module

module BVCheck8
  use export bv.BV8

  constant bv_size : t = 8
  constant two_power_size_minus_one : int = 0x80
  constant minus_one : t = 0xFF
  constant min_sint : t = 0x80
  constant max_sint : t = 0x7F
  constant max_uint : t = 0xFF

  use bv.BVConverter_8_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant bv_size = bv_size,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end

module BVCheck16
  use export bv.BV16

  constant bv_size : t = 16
  constant two_power_size_minus_one : int = 0x8000
  constant minus_one : t = 0xFFFF
  constant min_sint : t = 0x8000
  constant max_sint : t = 0x7FFF
  constant max_uint : t = 0xFFFF

  use bv.BVConverter_16_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant bv_size = bv_size,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end

module BVCheck32
  use export bv.BV32

  constant bv_size : t = 32
  constant two_power_size_minus_one : int = 0x8000_0000
  constant minus_one : t = 0xFFFF_FFFF
  constant min_sint : t = 0x8000_0000
  constant max_sint : t = 0x7FFF_FFFF
  constant max_uint : t = 0xFFFF_FFFF

  use bv.BVConverter_32_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant bv_size = bv_size,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end

module BVCheck64
  use export bv.BV64

  constant bv_size : t = 64
  constant two_power_size_minus_one : int = 0x8000_0000_0000_0000
  constant minus_one : t = 0xFFFF_FFFF_FFFF_FFFF
  constant min_sint : t = 0x8000_0000_0000_0000
  constant max_sint : t = 0x7FFF_FFFF_FFFF_FFFF
  constant max_uint : t = 0xFFFF_FFFF_FFFF_FFFF

  use bv.BVConverter_64_128

  clone export BVCheck_Gen with
    type t = t,
    constant size = size,
    constant bv_size = bv_size,
    function two_power_size = two_power_size,
    function two_power_size_minus_one = two_power_size_minus_one,
    function zeros = zeros,
    function minus_one = minus_one,
    function min_sint = min_sint,
    function max_sint = max_sint,
    function max_uint = max_uint,
    function to_uint = t'int,
    function to_int = to_int,
    function of_int = of_int,
    function add = add,
    function sub = sub,
    function mul = mul,
    function udiv = udiv,
    function urem = urem,
    function sdiv = sdiv,
    function srem = srem,
    function lsl = lsl,
    function lsl_bv = lsl_bv,
    function lsr = lsr,
    function lsr_bv = lsr_bv,
    function asr = asr,
    function asr_bv = asr_bv,
    predicate ule = ule,
    predicate ult = ult,
    predicate uge = uge,
    predicate ugt = ugt,
    predicate sle = sle,
    predicate slt = slt,
    predicate sge = sge,
    predicate sgt = sgt,
    function sto_bv128 = stoBig,
    function uto_bv128 = toBig
end

Generated by why3doc 1.7.2