	module M = Stdint.Int32
	type int32 = M.t
	let n = Prims.of_int 32

	let int_to_t x = M.of_string (Z.to_string x)
	let __int_to_t = int_to_t
(* This .ml.body file is concatenated to every .ml.prefix file in this
 * directory (ulib/ml/) to generate the OCaml realizations for machine
 * integers, as they all pretty much share their definitions and are
 * based on Stdint. *)

type t = M.t

let v (x:t) : Prims.int = Prims.parse_int (M.to_string x)

let zero = M.zero
let one  = M.one
let ones = M.pred M.zero

(* Reexport add, plus aliases *)
let add           = M.add
let add_underspec = M.add
let add_mod       = M.add

(* Reexport sub, plus aliases *)
let sub           = M.sub
let sub_underspec = M.sub
let sub_mod       = M.sub

(* Reexport mul, plus aliases *)
let mul           = M.mul
let mul_underspec = M.mul
let mul_mod       = M.mul

(* Conversions to Zarith's int *)
let to_int (x:t) : Z.t = Z.of_string (M.to_string x)
let of_int (x:Z.t) : t = M.of_string (Z.to_string x)

(* Conversion to native ints; these are potentially unsafe and not part
 * of the interface: they are meant to be called only from OCaml code
 * that is doing the right thing *)
let of_native_int (x:int) : t = M.of_int x
let to_native_int (x:t) : int = M.to_int x

(* Just reexport these *)
let div           = M.div
let rem           = M.rem
let logand        = M.logand
let logxor        = M.logxor
let logor         = M.logor
let lognot        = M.lognot
let to_string     = M.to_string
let of_string     = M.of_string

let to_string_hex = M.to_string_hex

let to_string_hex_pad i =
    let s0 = M.to_string_hex i in
    let len = (String.length s0 - 2) in
    let s1 = String.sub s0 2 len in (* Remove leading "0x" *)
    let zeroes = String.make ((Z.to_int n / 4) - len) '0' in
    zeroes ^ s1

(* The shifts take a uint32 argument, so we need to convert *)
let shift_right n i  = M.shift_right n (Stdint.Uint32.to_int i)
let shift_left  n i  = M.shift_left n (Stdint.Uint32.to_int i)
let shift_arithmetic_right = shift_right

(* Rotate operations - the shift amount is a uint32.
 * Converting uint32 to native int may truncate on 32-bit machines (values >= 2^31),
 * but the subsequent modulo operation ensures amount is in range [0, bitwidth-1],
 * making the result safe regardless of any truncation in the conversion. *)
let rotate_left a i =
  let amount = (Stdint.Uint32.to_int i) mod (Z.to_int n) in
  M.logor (M.shift_left a amount) (M.shift_right a ((Z.to_int n) - amount))

let rotate_right a i =
  let amount = (Stdint.Uint32.to_int i) mod (Z.to_int n) in
  M.logor (M.shift_right a amount) (M.shift_left a ((Z.to_int n) - amount))

(* Comparison operators *)
let eq  (a:t) (b:t) : bool = a = b
let ne  (a:t) (b:t) : bool = a <> b
let gt  (a:t) (b:t) : bool = a > b
let gte (a:t) (b:t) : bool = a >= b
let lt  (a:t) (b:t) : bool = a < b
let lte (a:t) (b:t) : bool = a <= b

(* NOT Constant time operators *)
let eq_mask  (a:t) (b:t) : t = if a  = b then ones else zero
let gte_mask (a:t) (b:t) : t = if a >= b then ones else zero
