Summary: On some pathological examples of crypto primitives like libsodium, later diffs make pulse grind to a halt due to an explosion in the size of literals. This is at least partly due to the fact the arithmetic doesn't operate modulo 2^64. Due to the fact the arithmetic is confused in any case when we reach such large numbers, cap them, currently at 2^128. This removes pathological cases for now, even now on libsodium Pulse is ~5 times faster than before! Take this opportunity to put the modified Q/Z modules in the own files. Reviewed By: jberdine Differential Revision: D27463933 fbshipit-source-id: 342d941e2master
parent
2d83dfdcb0
commit
d1b3e56574
@ -0,0 +1,47 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
module Z = ZSafe
|
||||
include Q
|
||||
|
||||
type _q = Q.t = {num: Z.t; den: Z.t} [@@deriving yojson_of]
|
||||
|
||||
let yojson_of_t = [%yojson_of: _q]
|
||||
|
||||
let not_equal q1 q2 = not (Q.equal q1 q2)
|
||||
|
||||
let is_one q = Q.equal q Q.one
|
||||
|
||||
let is_minus_one q = Q.equal q Q.minus_one
|
||||
|
||||
let is_zero q = Q.equal q Q.zero
|
||||
|
||||
let is_not_zero q = not (is_zero q)
|
||||
|
||||
let to_int q = Z.protect Q.to_int q
|
||||
|
||||
let to_int32 q = Z.protect Q.to_int32 q
|
||||
|
||||
let to_int64 q = Z.protect Q.to_int64 q
|
||||
|
||||
let to_bigint q = Z.protect Q.to_bigint q
|
||||
|
||||
let to_nativeint q = Z.protect Q.to_nativeint q
|
||||
|
||||
(** cap certain operations to prevent numerators and denominators from growing too large (>128 bits
|
||||
on a 64-bit machine) *)
|
||||
let cap q = if Int.(Z.size q.num > 2 || Z.size q.den > 2) then Q.undef else q
|
||||
|
||||
let mul q1 q2 =
|
||||
(* {!Q.mul} does not optimise these cases *)
|
||||
if is_one q1 then q2 else if is_one q2 then q1 else Q.mul q1 q2 |> cap
|
||||
|
||||
|
||||
let div q1 q2 =
|
||||
(* {!Q.div} does not optimise these cases *)
|
||||
if is_one q2 then q1 else Q.div q1 q2
|
@ -0,0 +1,39 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
(* OCaml needs to know not only that this has the same interface as [Q] but also that the types it
|
||||
defines are, in fact, the same as [Q] *)
|
||||
include module type of struct
|
||||
include Q
|
||||
end
|
||||
|
||||
val yojson_of_t : [%yojson_of: t]
|
||||
|
||||
val is_zero : t -> bool
|
||||
|
||||
val is_not_zero : t -> bool
|
||||
|
||||
val is_one : t -> bool
|
||||
|
||||
val is_minus_one : t -> bool
|
||||
|
||||
val not_equal : t -> t -> bool
|
||||
|
||||
(* the functions below shadow definitions in [Q] to give them safer types *)
|
||||
[@@@warning "-32"]
|
||||
|
||||
val to_int : t -> int option
|
||||
|
||||
val to_int32 : t -> int32 option
|
||||
|
||||
val to_int64 : t -> int64 option
|
||||
|
||||
val to_bigint : t -> Z.t option
|
||||
|
||||
val to_nativeint : t -> nativeint option
|
@ -0,0 +1,58 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
let protect f x = try Some (f x) with Division_by_zero | Invalid_argument _ | Z.Overflow -> None
|
||||
|
||||
let protect2 f x y =
|
||||
try Some (f x y) with Division_by_zero | Invalid_argument _ | Z.Overflow -> None
|
||||
|
||||
|
||||
let yojson_of_t z = `String (Z.to_string z)
|
||||
|
||||
include Z
|
||||
|
||||
let div = protect2 Z.div
|
||||
|
||||
let rem = protect2 Z.rem
|
||||
|
||||
let div_rem = protect2 Z.div_rem
|
||||
|
||||
let cdiv = protect2 Z.cdiv
|
||||
|
||||
let fdiv = protect2 Z.fdiv
|
||||
|
||||
let ediv_rem = protect2 Z.ediv_rem
|
||||
|
||||
let ediv = protect2 Z.ediv
|
||||
|
||||
let erem = protect2 Z.erem
|
||||
|
||||
let divexact = protect2 Z.divexact
|
||||
|
||||
let gcd = protect2 Z.gcd
|
||||
|
||||
let gcdext = protect2 Z.gcdext
|
||||
|
||||
let lcm = protect2 Z.lcm
|
||||
|
||||
let powm = protect2 Z.powm
|
||||
|
||||
let powm_sec = protect2 Z.powm_sec
|
||||
|
||||
let invert = protect2 Z.invert
|
||||
|
||||
let ( / ) = protect2 Z.( / )
|
||||
|
||||
let ( /> ) = protect2 Z.( /> )
|
||||
|
||||
let ( /< ) = protect2 Z.( /< )
|
||||
|
||||
let ( /| ) = protect2 Z.( /| )
|
||||
|
||||
let ( mod ) = protect2 Z.( mod )
|
@ -0,0 +1,62 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
|
||||
(* OCaml needs to know not only that this has the same interface as [Z] but also that the types it
|
||||
defines are, in fact, the same as [Z] *)
|
||||
include module type of struct
|
||||
include Z
|
||||
end
|
||||
|
||||
val protect : ('a -> 'b) -> 'a -> 'b option
|
||||
(** [None] instead of throwing [Division_by_zero | Invalid_argument _ | Z.Overflow] *)
|
||||
|
||||
val yojson_of_t : [%yojson_of: t]
|
||||
|
||||
(* the functions below shadow definitions in [Z] to give them safer types *)
|
||||
[@@@warning "-32"]
|
||||
|
||||
val div : t -> t -> t option
|
||||
|
||||
val rem : t -> t -> t option
|
||||
|
||||
val div_rem : t -> t -> (t * t) option
|
||||
|
||||
val cdiv : t -> t -> t option
|
||||
|
||||
val fdiv : t -> t -> t option
|
||||
|
||||
val ediv_rem : t -> t -> (t * t) option
|
||||
|
||||
val ediv : t -> t -> t option
|
||||
|
||||
val erem : t -> t -> t option
|
||||
|
||||
val divexact : t -> t -> t option
|
||||
|
||||
val gcd : t -> t -> t option
|
||||
|
||||
val gcdext : t -> t -> (t * t * t) option
|
||||
|
||||
val lcm : t -> t -> t option
|
||||
|
||||
val powm : t -> t -> (t -> t) option
|
||||
|
||||
val powm_sec : t -> t -> (t -> t) option
|
||||
|
||||
val invert : t -> t -> t option
|
||||
|
||||
val ( / ) : t -> t -> t option
|
||||
|
||||
val ( /> ) : t -> t -> t option
|
||||
|
||||
val ( /< ) : t -> t -> t option
|
||||
|
||||
val ( /| ) : t -> t -> t option
|
||||
|
||||
val ( mod ) : t -> t -> t option
|
Loading…
Reference in new issue