[m-rev.] for review: add a system RNG implementation for the C backends on Linux

Julien Fischer jfischer at opturion.com
Sun Jan 31 15:15:34 AEDT 2021


For review by anyone.

------------------------

Add a system RNG implementation for the C backends on Linux.

Add a system RNG implementation for the C backends on Linux that works by
reading random bits from /dev/urandom. We will eventually provide a version
that reads from getrandom() on Linux systems that provide that; this
implementation is a fallback for those system that do not.  (It may also
be what we use on other Unix-like system that do not provide anything
better.)

runtime/mercury_random.h:
runtime/mercury_random.c:
     Add new runtime module that provides the interface to the system
     RNG for the C backends.

     Add two implementations of the system RNG, one that reads from
     /dev/urandom and one that just aborts.  The former is used on
     Linux and the latter is used everywhere else (for now).

runtime/Mmakefile:
     Add the new files.

library/random.system_rng.m:
     Add C foreign procs for the predicates in this module that
     forward all their work to the new runtime module.

Julien.

diff --git a/library/random.system_rng.m b/library/random.system_rng.m
index 872058c..affd2c4 100644
--- a/library/random.system_rng.m
+++ b/library/random.system_rng.m
@@ -84,16 +84,19 @@

  :- import_module bool.
  :- import_module exception.
+:- import_module list.
+:- import_module string.

  %---------------------------------------------------------------------------%

-:- pragma foreign_type("Java", system_rng,
-    "java.security.SecureRandom").
+:- pragma foreign_decl("C", "#include \"mercury_random.h\"").
+
+:- pragma foreign_type("C", system_rng, "MR_SystemRandomHandle",
+    [can_pass_as_mercury_type]).
  :- pragma foreign_type("C#", system_rng,
      "System.Security.Cryptography.RandomNumberGenerator").
-
-:- type system_rng
-    --->    system_rng.
+:- pragma foreign_type("Java", system_rng,
+    "java.security.SecureRandom").

  %---------------------------------------------------------------------------%

@@ -114,6 +117,17 @@

  %---------------------------------------------------------------------------%

+:- pragma foreign_proc("C",
+    have_system_rng,
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+#if defined(MR_SYSRAND_IMPL_NONE)
+    SUCCESS_INDICATOR = MR_FALSE;
+#else
+    SUCCESS_INDICATOR = MR_TRUE;
+#endif
+").
+
  :- pragma foreign_proc("C#",
      have_system_rng,
      [will_not_call_mercury, promise_pure, thread_safe],
@@ -128,9 +142,6 @@
      SUCCESS_INDICATOR = true;
  ").

-have_system_rng :-
-    semidet_false.
-
  %---------------------------------------------------------------------------%

  open_system_rng(Result, !IO) :-
@@ -146,6 +157,14 @@ open_system_rng(Result, !IO) :-
  :- pred do_open_system_rng(system_rng::out, bool::out, string::out,
      io::di, io::uo) is det.

+:- pragma foreign_proc("C",
+    do_open_system_rng(Handle::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    Handle = MR_random_open(&IsOk, &ErrorMsg);
+").
+
  :- pragma foreign_proc("C#",
      do_open_system_rng(Handle::out, IsOk::out, ErrorMsg::out,
          _IO0::di, _IO::uo),
@@ -167,11 +186,6 @@ open_system_rng(Result, !IO) :-
      ErrorMsg = \"\";
  ").

-do_open_system_rng(Handle, IsOk, ErrorMsg, !IO) :-
-    Handle = system_rng,
-    IsOk = no,
-    ErrorMsg = "No system RNG available".
-
  %---------------------------------------------------------------------------%

  close_system_rng(Handle, !IO) :-
@@ -180,12 +194,20 @@ close_system_rng(Handle, !IO) :-
          IsOk = yes
      ;
          IsOk = no,
-        throw(software_error(ErrorMsg))
+        throw_system_rng_error($pred, ErrorMsg)
      ).

  :- pred do_close_system_rng(system_rng::in, bool::out, string::out,
      io::di, io::uo) is det.

+:- pragma foreign_proc("C",
+    do_close_system_rng(Handle::in, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe],
+"
+    IsOk = MR_random_close(Handle, &ErrorMsg);
+").
+
  :- pragma foreign_proc("C#",
      do_close_system_rng(Handle::in, IsOk::out, ErrorMsg::out,
          _IO0::di, _IO::uo),
@@ -206,95 +228,193 @@ close_system_rng(Handle, !IO) :-
      ErrorMsg = \"\";
  ").

-do_close_system_rng(_, _, _, _, _) :-
-    private_builtin.sorry("No system RNG available").
-
  %---------------------------------------------------------------------------%

+generate_uint8(Handle, U8, !IO) :-
+    do_generate_uint8(Handle, U8, IsOk, ErrorMsg, !IO),
+    (
+        IsOk = yes
+    ;
+        IsOk = no,
+        throw_system_rng_error($pred, ErrorMsg)
+    ).
+
+:- pred do_generate_uint8(system_rng::in, uint8::out, bool::out,
+    string::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_generate_uint8(Handle::in, U8::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    U8 = MR_random_generate_uint8(Handle, &IsOk, &ErrorMsg);
+").
+
  :- pragma foreign_proc("C#",
-    generate_uint8(Handle::in, U8::out, _IO0::di, _IO::uo),
+    do_generate_uint8(Handle::in, U8::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      byte[] bytes = new byte[1];
      Handle.GetBytes(bytes);
      U8 = bytes[0];
+    IsOk = mr_bool.YES;
+    ErrorMsg = \"\";
  ").

  :- pragma foreign_proc("Java",
-    generate_uint8(Handle::in, U8::out, _IO0::di, _IO::uo),
+    do_generate_uint8(Handle::in, U8::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      byte[] bytes = new byte[1];
      Handle.nextBytes(bytes);
      U8 = bytes[0];
+    IsOk = bool.YES;
+    ErrorMsg = \"\";
  ").

-generate_uint8(_, _, !IO) :-
-    private_builtin.sorry("No system RNG available").
-
  %---------------------------------------------------------------------------%

+generate_uint16(Handle, U16, !IO) :-
+    do_generate_uint16(Handle, U16, IsOk, ErrorMsg, !IO),
+    (
+        IsOk = yes
+    ;
+        IsOk = no,
+        throw_system_rng_error($pred, ErrorMsg)
+    ).
+
+:- pred do_generate_uint16(system_rng::in, uint16::out, bool::out,
+    string::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_generate_uint16(Handle::in, U16::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    U16 = MR_random_generate_uint16(Handle, &IsOk, &ErrorMsg);
+").
+
  :- pragma foreign_proc("C#",
-    generate_uint16(Handle::in, U16::out, _IO0::di, _IO::uo),
+    do_generate_uint16(Handle::in, U16::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, not_thread_safe],
  "
      byte[] bytes = new byte[2];
      Handle.GetBytes(bytes);
      U16 = (ushort) System.BitConverter.ToInt16(bytes);
+    IsOk = mr_bool.YES;
+    ErrorMsg = \"\";
  ").

  :- pragma foreign_proc("Java",
-    generate_uint16(Handle::in, U16::out, _IO0::di, _IO::uo),
+    do_generate_uint16(Handle::in, U16::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      byte[] bytes = new byte[2];
      Handle.nextBytes(bytes);
      U16 = (short) (bytes[0] << java.lang.Byte.SIZE | (bytes[1] & 0x00ff));
+    IsOk = bool.YES;
+    ErrorMsg = \"\";
  ").

-generate_uint16(_, _, !IO) :-
-    private_builtin.sorry("No system RNG available").
-
  %---------------------------------------------------------------------------%

+generate_uint32(Handle, U32, !IO) :-
+    do_generate_uint32(Handle, U32, IsOk, ErrorMsg, !IO),
+    (
+        IsOk = yes
+    ;
+        IsOk = no,
+        throw_system_rng_error($pred, ErrorMsg)
+    ).
+
+:- pred do_generate_uint32(system_rng::in, uint32::out, bool::out,
+    string::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_generate_uint32(Handle::in, U32::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    U32 = MR_random_generate_uint32(Handle, &IsOk, &ErrorMsg);
+").
+
  :- pragma foreign_proc("C#",
-    generate_uint32(Handle::in, U32::out, _IO0::di, _IO::uo),
+    do_generate_uint32(Handle::in, U32::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, not_thread_safe],
  "
      byte[] bytes = new byte[4];
      Handle.GetBytes(bytes);
      U32 = (uint) System.BitConverter.ToInt32(bytes);
+    IsOk = mr_bool.YES;
+    ErrorMsg = \"\";
  ").

  :- pragma foreign_proc("Java",
-    generate_uint32(Handle::in, U32::out, _IO0::di, _IO::uo),
+    do_generate_uint32(Handle::in, U32::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      U32 = Handle.nextInt();
+    IsOk = bool.YES;
+    ErrorMsg = \"\";
  ").
-generate_uint32(_, _, !IO) :-
-    private_builtin.sorry("No system RNG available").

  %---------------------------------------------------------------------------%

+generate_uint64(Handle, U64, !IO) :-
+    do_generate_uint64(Handle, U64, IsOk, ErrorMsg, !IO),
+    (
+        IsOk = yes
+    ;
+        IsOk = no,
+        throw_system_rng_error($pred, ErrorMsg)
+    ).
+
+:- pred do_generate_uint64(system_rng::in, uint64::out, bool::out,
+    string::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+    do_generate_uint64(Handle::in, U64::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+    U64 = MR_random_generate_uint64(Handle, &IsOk, &ErrorMsg);
+").
+
  :- pragma foreign_proc("C#",
-    generate_uint64(Handle::in, U64::out, _IO0::di, _IO::uo),
+    do_generate_uint64(Handle::in, U64::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, not_thread_safe],
  "
      byte[] bytes = new byte[8];
      Handle.GetBytes(bytes);
      U64 = (ulong) System.BitConverter.ToInt64(bytes);
+    IsOk = mr_bool.YES;
+    ErrorMsg = \"\";
  ").

  :- pragma foreign_proc("Java",
-    generate_uint64(Handle::in, U64::out, _IO0::di, _IO::uo),
+    do_generate_uint64(Handle::in, U64::out, IsOk::out, ErrorMsg::out,
+        _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      U64 = Handle.nextLong();
+    IsOk = bool.YES;
+    ErrorMsg = \"\";
  ").

-generate_uint64(_, _, !IO) :-
-    private_builtin.sorry("No system RNG available").
+%---------------------------------------------------------------------------%
+
+:- pred throw_system_rng_error(string::in, string::in) is erroneous.
+
+throw_system_rng_error(Pred, Msg) :-
+    string.format("%s: %s", [s(Pred), s(Msg)], Error),
+    throw(software_error(Error)).

  %---------------------------------------------------------------------------%
  :- end_module random.system_rng.
diff --git a/runtime/Mmakefile b/runtime/Mmakefile
index 8e7beb1..45939dc 100644
--- a/runtime/Mmakefile
+++ b/runtime/Mmakefile
@@ -79,6 +79,7 @@ HDRS = \
  	mercury_prof_mem.h			\
  	mercury_prof_time.h			\
  	mercury_profiling_builtin.h		\
+	mercury_random.h			\
  	mercury_reg_workarounds.h		\
  	mercury_region.h			\
  	mercury_regs.h				\
@@ -194,6 +195,7 @@ CFILES = \
  	mercury_prof_mem.c			\
  	mercury_prof_time.c			\
  	mercury_profiling_builtin.c		\
+	mercury_random.c			\
  	mercury_reg_workarounds.c		\
  	mercury_region.c			\
  	mercury_regs.c				\
diff --git a/runtime/mercury_random.c b/runtime/mercury_random.c
index e69de29..85a1025 100644
--- a/runtime/mercury_random.c
+++ b/runtime/mercury_random.c
@@ -0,0 +1,214 @@
+// vim: ts=4 sw=4 expandtab ft=c
+
+// Copyright (C) 2021 The Mercury team.
+// This file is distributed under the terms specified in COPYING.LIB.
+
+// mercury_random.c
+
+#include "mercury_memory.h"
+#include "mercury_misc.h"
+#include "mercury_random.h"
+#include "mercury_runtime_util.h"
+#include "mercury_std.h"
+#include "mercury_string.h"
+#include "mercury_types.h"
+
+#if defined(MR_HAVE_UNISTD_H)
+    #include <unistd.h>
+#endif 
+#if defined(MR_HAVE_FCNTL_H)
+    #include <fcntl.h>
+#endif
+#if defined(MR_HAVE_SYS_STATH)
+    #include <sys/stat.h>
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(MR_SYSRAND_IMPL_URANDOM)
+
+static MR_Bool
+read_bytes_from_urandom(int fd, void *buffer, size_t n,
+    MR_String *err_msg);
+
+MR_SystemRandomHandle
+MR_random_open(MR_Bool *succeeded, MR_String *err_msg)
+{
+    int fd;
+    char errbuf[MR_STRERROR_BUF_SIZE]; 
+    MR_SystemRandomHandle handle;
+
+    do {
+        fd = open("/dev/urandom", O_RDONLY);
+    } while (fd == -1 && MR_is_eintr(errno));
+
+    if (fd == -1) {
+        MR_strerror(errno, errbuf, sizeof(errbuf));
+        MR_save_transient_hp();
+        MR_make_aligned_string_copy(*err_msg, errbuf);
+        MR_restore_transient_hp();
+        *succeeded = MR_NO;
+        handle = NULL;
+    } else {
+        handle =
+            MR_GC_malloc(sizeof(struct MR_SystemRandomHandle_Struct));
+        handle->MR_srh_fd = fd;
+        *err_msg = MR_make_string_const("");
+        *succeeded = MR_YES;
+    }
+ 
+    return handle;
+}
+
+MR_Bool
+MR_random_close(MR_SystemRandomHandle handle, MR_String *err_msg)
+{
+    char errbuf[MR_STRERROR_BUF_SIZE]; 
+
+    if (close(handle->MR_srh_fd) == -1) {
+        MR_strerror(errno, errbuf, sizeof(errbuf));
+        MR_save_transient_hp();
+        MR_make_aligned_string_copy(*err_msg, errbuf);
+        MR_restore_transient_hp();
+        return MR_NO;
+    } else {
+        handle->MR_srh_fd = -1;
+        *err_msg = MR_make_string_const("");
+        return MR_YES;
+    }
+}
+
+uint8_t
+MR_random_generate_uint8(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    unsigned char buffer[1];
+    if (read_bytes_from_urandom(handle->MR_srh_fd, buffer, 1, err_msg)) {
+        *succeeded = MR_TRUE;
+        return (uint8_t) buffer[0];
+    } else {
+        *succeeded = MR_FALSE;
+        return 0;
+    }
+}
+
+uint16_t
+MR_random_generate_uint16(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    uint16_t n;
+    unsigned char *buffer = (unsigned char *) &n;
+    if (read_bytes_from_urandom(handle->MR_srh_fd, buffer, 2, err_msg)) {
+        *succeeded = MR_TRUE;
+        return n;
+    } else {
+        *succeeded = MR_FALSE;
+        return 0;
+    }
+}
+
+uint32_t
+MR_random_generate_uint32(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    uint32_t n;
+    unsigned char *buffer = (unsigned char *) &n;
+    if (read_bytes_from_urandom(handle->MR_srh_fd, buffer, 4, err_msg)) {
+        *succeeded = MR_TRUE;
+        return n;
+    } else {
+        *succeeded = MR_FALSE;
+        return 0;
+    }
+}
+
+uint64_t
+MR_random_generate_uint64(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    uint64_t n;
+    unsigned char *buffer = (unsigned char *) &n;
+    if (read_bytes_from_urandom(handle->MR_srh_fd, buffer, 8, err_msg)) {
+        *succeeded = MR_TRUE;
+        return n;
+    } else {
+        *succeeded = MR_FALSE;
+        return 0;
+    }
+}
+
+MR_Bool
+read_bytes_from_urandom(int fd, void *buffer, size_t n,
+    MR_String *err_msg)
+{
+    int i;
+    char errbuf[MR_STRERROR_BUF_SIZE]; 
+
+    for (i = 0; i < n; ) {
+        size_t to_read = n - i;
+        ssize_t bytes_read = read(fd, buffer, to_read);
+        if (bytes_read == -1) {
+            if (MR_is_eintr(errno)) {
+                continue;
+            } else {
+                MR_strerror(errno, errbuf, sizeof(errbuf));
+                MR_save_transient_hp();
+                MR_make_aligned_string_copy(*err_msg, errbuf);
+                MR_restore_transient_hp();
+                return MR_FALSE;
+            }
+        }
+        i += bytes_read;
+    }
+
+    *err_msg = MR_make_string_const("");
+    return MR_TRUE;
+}
+
+#else // MR_SYSRAND_IMPL_NONE
+
+MR_SystemRandomHandle
+MR_random_open(MR_Bool *succeeded, MR_String *err_msg)
+{
+    succeeded = MR_FALSE;
+    *err_msg = MR_make_string_const("No system RNG available");
+    return 0; // Dummy value.
+}
+
+MR_Bool
+MR_random_close(MR_SystemRandomHandle handle, MR_String *err_msg)
+{
+    MR_fatal_error("MR_random_close - no system RNG available.");
+}
+
+uint8_t
+MR_random_generate_uint8(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    MR_fatal_error("MR_random_generate_uint8 - no system RNG available.");
+}
+
+uint16_t
+MR_random_generate_uint16(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    MR_fatal_error("MR_random_genereate_uint16 - No system RNG available.");
+}
+
+uint32_t
+MR_random_generate_uint32(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    MR_fatal_error("MR_random_generate_uint32 - no system RNG available.");
+}
+
+uint64_t
+MR_random_generate_uint64(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg)
+{
+    MR_fatal_error("MR_random_generate_uint64 - no system RNG available.");
+}
+
+#endif
diff --git a/runtime/mercury_random.h b/runtime/mercury_random.h
index e69de29..8e29c78 100644
--- a/runtime/mercury_random.h
+++ b/runtime/mercury_random.h
@@ -0,0 +1,97 @@
+// vim: ts=4 sw=4 expandtab ft=c
+
+// Copyright (C) 2021 The Mercury team.
+// This file is distributed under the terms specified in COPYING.LIB.
+
+// mercury_random.h - code for interacting with the system RNG.
+
+#ifndef MR_MERCURY_RANDOM_H
+#define MERCURY_RANDOM_H
+
+#include "mercury_conf_param.h"
+#include "mercury_types.h"
+#include "mercury_windows.h"
+
+#include <stdint.h>
+
+////////////////////////////////////////////////////////////////////////////
+//
+// The following macros define if the system random number exists on this
+// system and, if so, how it is accessed.
+//
+// Only one of the following must be defined.
+//
+// MR_SYSRAND_IMPL_ARC4RANDOM (NYI)
+//    the system RNG is implemented by calling the arc4random() family of
+//    functions. Note: this for when arc4random() is provided by libc (as on
+//    macOS and the BSDs), not for when it is provided as a separate library
+//    (e.g. libbsd on Linux).
+//
+// MR_SYSRAND_IMPL_RAND_S (NYI)
+//    the system RNG is implemented by calling the rand_s() function
+//    (Windows only).
+//
+// MR_SYSRAND_IMPL_GETRANDOM (NYI)
+//    the system RNG is implemented by calling getrandom() (sufficiently
+//    recent Linux kernels only).
+//
+// MR_SYSRAND_IMPL_URANDOM
+//     the system RNG is implemented by reading from /dev/urandom.
+//     (XXX currently only tested, and enabled, on Linux.)
+//
+// MR_SYSRAND_IMPL_NONE
+//     there is no system RNG is not available on this platform.
+
+#if defined(__linux__)
+    #define MR_SYSRAND_IMPL_URANDOM
+#else
+    #define MR_SYSRAND_IMPL_NONE
+#endif
+
+////////////////////////////////////////////////////////////////////////////
+
+#if defined(MR_SYSRAND_IMPL_URANDOM)
+    struct MR_SystemRandomHandle_Struct {
+        int MR_srh_fd;
+    };
+    typedef struct MR_SystemRandomHandle_Struct *MR_SystemRandomHandle;
+#else
+    typedef MR_Unsigned MR_SystemRandomHandle;
+#endif
+
+
+// When succeeded is MR_TRUE, returns a handle through which the system
+// RNG can be accessed; err_msg will point to the empty string in this case.
+// When succeeded is MR_FALSE, the value return is not a valid handle and
+// err_msg will point ot a string (on the Mercury heap) describing why a handle
+// for the system RNG could not be acquired.
+//
+extern MR_SystemRandomHandle MR_random_open(MR_Bool *succeeded,
+    MR_String *err_msg);
+
+// Attempt to close the handle to the system RNG.
+// Returns MR_TRUE on success with err_msg pointing to the empty string.
+// Returns MR_FALSE on failure with err_msg pointing to a string (on the
+// Mercury heap) that describes whey the handle could not be closed.
+//
+extern MR_Bool MR_random_close(MR_SystemRandomHandle handle, MR_String *err_msg);
+
+
+// If succeeded is MR_TRUE then these functions return a randomly generated
+// unsigned integer of the requested size generated through the given system
+// RNG handle; err_msg will point to the empty string.
+//
+// If succeeded is MR_FALSE, the system RNG has been unable to generate the
+// random unsigned integer; in this case zero will be returned and err_msg will
+// point to a string (on the Mercury heap) that describes the problem.
+//
+extern uint8_t MR_random_generate_uint8(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_smg);
+extern uint16_t MR_random_generate_uint16(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg);
+extern uint32_t MR_random_generate_uint32(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg);
+extern uint64_t MR_random_generate_uint64(MR_SystemRandomHandle handle,
+    MR_Bool *succeeded, MR_String *err_msg);
+
+#endif // MR_MERCURY_RANDOM_H


More information about the reviews mailing list