Skip to content

Commit

Permalink
Use standard hash function for Z.hash and add Z.seeded_hash
Browse files Browse the repository at this point in the history
For consistency with other integer types in the standard library
(modules Int, Int32, Int64, Nativeint), let's use the standard
hash function (`Hashtbl.hash`) for `Z.hash` instead of our variant.

This is a bit slower but has several benefits (see ocaml#145):
- 32/64 bit compatibility
- better mixing of the bits of the result.

While we're at it, add a `Z.seeded_hash` function, defined as
`Hashtbl.seeded_hash`, so that the `Z` module can be used as the argument
to the `Hashtbl.MakeSeeded` functor.
  • Loading branch information
xavierleroy committed Dec 28, 2023
1 parent 524a489 commit cf2f944
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 11 deletions.
5 changes: 0 additions & 5 deletions caml_z.c
Original file line number Diff line number Diff line change
Expand Up @@ -3350,11 +3350,6 @@ static intnat ml_z_custom_hash(value v)
return acc;
}

CAMLprim value ml_z_hash(value v)
{
return Val_long(ml_z_custom_hash(v));
}

/* serialized format:
- 1-byte sign (1 for negative, 0 for positive)
- 4-byte size in bytes
Expand Down
3 changes: 2 additions & 1 deletion z.ml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ external perfect_power: t -> bool = "ml_z_perfect_power"
external perfect_square: t -> bool = "ml_z_perfect_square"
external probab_prime: t -> int -> int = "ml_z_probab_prime"
external nextprime: t -> t = "ml_z_nextprime"
external hash: t -> int = "ml_z_hash" [@@noalloc]
let hash: t -> int = Stdlib.Hashtbl.hash
let seeded_hash: int -> t -> int = Stdlib.Hashtbl.seeded_hash
external to_bits: t -> string = "ml_z_to_bits"
external of_bits: string -> t = "ml_z_of_bits"

Expand Down
28 changes: 23 additions & 5 deletions z.mli
Original file line number Diff line number Diff line change
Expand Up @@ -486,12 +486,24 @@ val is_odd: t -> bool
@since 1.4
*)

external hash: t -> int = "ml_z_hash" [@@noalloc]
val hash: t -> int
(** Hashes a number, producing a small integer.
The result is consistent with equality: if [a] = [b], then [hash a] =
[hash b].
OCaml's generic hash function, [Hashtbl.hash], works correctly with
numbers, but {!Z.hash} is slightly faster.
The result is consistent with equality:
if [a] = [b], then [hash a] = [hash b].
The result is the same as produced by OCaml's generic hash function,
{!Hashtbl.hash}.
Together with type {!Z.t}, the function {!Z.hash} makes it possible
to pass module {!Z} as argument to the functor {!Hashtbl.Make}.
@before 1.14 a different hash algorithm was used.
*)

val seeded_hash: int -> t -> int
(** Like {!Z.hash}, but takes a seed as extra argument for diversification.
The result is the same as produced by OCaml's generic seeded hash function,
{!Hashtbl.seeded_hash}.
Together with type {!Z.t}, the function {!Z.hash} makes it possible
to pass module {!Z} as argument to the functor {!Hashtbl.MakeSeeded}.
@since 1.14
*)

(** {1 Elementary number theory} *)
Expand Down Expand Up @@ -717,6 +729,8 @@ val random_int: ?rng: Random.State.t -> t -> t
Random numbers produced by this function are not cryptographically
strong and must not be used in cryptographic or high-security
contexts. See {!Z.random_int_gen} for an alternative.
@since 1.13
*)

val random_bits: ?rng: Random.State.t -> int -> t
Expand All @@ -731,6 +745,8 @@ val random_bits: ?rng: Random.State.t -> int -> t
Random numbers produced by this function are not cryptographically
strong and must not be used in cryptographic or high-security
contexts. See {!Z.random_bits_gen} for an alternative.
@since 1.13
*)

val random_int_gen: fill: (bytes -> int -> int -> unit) -> t -> t
Expand All @@ -751,6 +767,7 @@ val random_int_gen: fill: (bytes -> int -> int -> unit) -> t -> t
<<
Z.random_int_gen ~fill:Cryptokit.Random.secure_rng#bytes bound
>>
@since 1.13
*)

val random_bits_gen: fill: (bytes -> int -> int -> unit) -> int -> t
Expand All @@ -759,6 +776,7 @@ val random_bits_gen: fill: (bytes -> int -> int -> unit) -> int -> t
This is a more efficient special case of {!Z.random_int_gen} when the
bound is a power of two. The [fill] parameter is as described in
{!Z.random_int_gen}.
@since 1.13
*)

(** {1 Prefix and infix operators} *)
Expand Down

0 comments on commit cf2f944

Please sign in to comment.