commit 6d0f65e757e3840588b0de5175400993ccc857f2
parent 1cfc01ff3b8b1dd26f98fa268fba021b1f9370a4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 1 Dec 2020 11:53:59 +0100
Add and test the ssp_rng_<read|write>_cstr functions
[De]serialize the RNG state into a C string, i.e. a null terminated
buffer of bytes.
Diffstat:
4 files changed, 186 insertions(+), 17 deletions(-)
diff --git a/src/ssp.h b/src/ssp.h
@@ -76,7 +76,9 @@ struct ssp_rng_type {
uint64_t (*get)(void* state);
res_T (*discard)(void* state, uint64_t n);
res_T (*read)(void* state, FILE* file);
+ res_T (*read_cstr)(void* state, const char* cstr);
res_T (*write)(const void* state, FILE* file);
+ res_T (*write_cstr)(const void* state, char* buf, const size_t sz, size_t* len);
double (*entropy)(const void* state);
uint64_t min;
@@ -202,15 +204,27 @@ ssp_rng_max
(struct ssp_rng* rng);
SSP_API res_T
-ssp_rng_write
- (const struct ssp_rng* rng,
+ssp_rng_read
+ (struct ssp_rng* rng,
FILE* stream);
SSP_API res_T
-ssp_rng_read
+ssp_rng_read_cstr
(struct ssp_rng* rng,
+ const char* cstr); /* Null terminated string */
+
+SSP_API res_T
+ssp_rng_write
+ (const struct ssp_rng* rng,
FILE* stream);
+SSP_API res_T
+ssp_rng_write_cstr
+ (const struct ssp_rng* rng,
+ char* buf, /* May be NULL */
+ const size_t bufsz, /* buf capacity */
+ size_t* len); /* May be NULL. #chars to write into buf without null char */
+
SSP_API double
ssp_rng_entropy
(const struct ssp_rng* rng);
diff --git a/src/ssp_rng.c b/src/ssp_rng.c
@@ -107,19 +107,19 @@ rng_kiss_read(void* data, FILE* file)
{
struct rng_kiss* rng = (struct rng_kiss*)data;
int n;
- res_T res = RES_OK;
ASSERT(data && file);
+ n = fscanf(file, "%u %u %u %u\n", &rng->x, &rng->y, &rng->z, &rng->c);
+ return (n == EOF || n < 4) ? RES_IO_ERR : RES_OK;
+}
- n = fscanf(file, "%u %u %u %u", &rng->x, &rng->y, &rng->z, &rng->c);
- if(n == EOF || n < 4) {
- res = RES_IO_ERR;
- goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
+static res_T
+rng_kiss_read_cstr(void* data, const char* cstr)
+{
+ struct rng_kiss* rng = (struct rng_kiss*)data;
+ int n;
+ ASSERT(data && cstr);
+ n = sscanf(cstr, "%u %u %u %u\n", &rng->x, &rng->y, &rng->z, &rng->c);
+ return (n == EOF || n < 4) ? RES_IO_ERR : RES_OK;
}
static res_T
@@ -133,6 +133,26 @@ rng_kiss_write(const void* data, FILE* file)
}
static res_T
+rng_kiss_write_cstr
+ (const void* data,
+ char* buf,
+ const size_t bufsz,
+ size_t* out_len)
+{
+ const struct rng_kiss* rng = (const struct rng_kiss*)data;
+ int len = 0;
+ ASSERT(data);
+
+ len = snprintf(buf, bufsz, "%u %u %u %u\n", rng->x, rng->y, rng->z, rng->c);
+ CHK(len > 0);
+ if((size_t)len >= (bufsz - 1/*null char*/)) {
+ buf[bufsz-1] = '\0';
+ }
+ if(out_len) *out_len = (size_t)len;
+ return RES_OK;
+}
+
+static res_T
rng_kiss_init(struct mem_allocator* allocator, void* data)
{
(void)allocator;
@@ -170,7 +190,9 @@ const struct ssp_rng_type ssp_rng_kiss = {
rng_kiss_get,
rng_kiss_discard,
rng_kiss_read,
+ rng_kiss_read_cstr,
rng_kiss_write,
+ rng_kiss_write_cstr,
rng_kiss_entropy,
0,
UINT32_MAX,
@@ -231,6 +253,37 @@ rng_cxx_write<RAN_NAMESPACE::random_device>(const void* data, FILE* file)
template<typename RNG>
static res_T
+rng_cxx_write_cstr
+ (const void* data,
+ char* buf,
+ const size_t bufsz,
+ size_t* out_len)
+{
+ int len = 0;
+ std::stringstream stream;
+ RNG* rng = (RNG*)data;
+ ASSERT(rng);
+ stream << *rng << std::endl;
+ len = snprintf(buf, bufsz, "%s", stream.str().c_str());
+ CHK(len > 0);
+ if((size_t)len >= (bufsz - 1/*null char*/)) {
+ buf[bufsz-1] = '\0';
+ }
+ if(out_len) *out_len = (size_t)len;
+ return RES_OK;
+}
+
+template<>
+res_T
+rng_cxx_write_cstr<RAN_NAMESPACE::random_device>
+ (const void* data, char* buf, const size_t bufsz, size_t* out_len)
+{
+ (void)data; (void)buf, (void)bufsz, (void)out_len;
+ return RES_BAD_OP;
+}
+
+template<typename RNG>
+static res_T
rng_cxx_read(void* data, FILE* file)
{
std::stringstream stream;
@@ -250,7 +303,27 @@ template<>
res_T
rng_cxx_read<RAN_NAMESPACE::random_device>(void* data, FILE* file)
{
- (void) data; (void) file;
+ (void) data; (void)file;
+ return RES_BAD_OP;
+}
+
+template<typename RNG>
+static res_T
+rng_cxx_read_cstr(void* data, const char* cstr)
+{
+ std::stringstream stream;
+ RNG* rng = (RNG*)data;
+ ASSERT(rng && cstr && cstr[strlen(cstr)-1] == '\n');
+ stream << std::string(cstr);
+ stream >> *rng;
+ return stream.fail() ? RES_IO_ERR : RES_OK;
+}
+
+template<>
+res_T
+rng_cxx_read_cstr<RAN_NAMESPACE::random_device>(void* data, const char* cstr)
+{
+ (void)data, (void)cstr;
return RES_BAD_OP;
}
@@ -318,7 +391,9 @@ const struct ssp_rng_type ssp_rng_mt19937_64 = {
rng_cxx_get<RAN_NAMESPACE::mt19937_64>,
rng_cxx_discard<RAN_NAMESPACE::mt19937_64>,
rng_cxx_read<RAN_NAMESPACE::mt19937_64>,
+ rng_cxx_read_cstr<RAN_NAMESPACE::mt19937_64>,
rng_cxx_write<RAN_NAMESPACE::mt19937_64>,
+ rng_cxx_write_cstr<RAN_NAMESPACE::mt19937_64>,
rng_cxx_entropy<RAN_NAMESPACE::mt19937_64>,
RAN_NAMESPACE::mt19937_64::min(),
RAN_NAMESPACE::mt19937_64::max(),
@@ -334,7 +409,9 @@ const struct ssp_rng_type ssp_rng_ranlux48 = {
rng_cxx_get<RAN_NAMESPACE::ranlux48>,
rng_cxx_discard<RAN_NAMESPACE::ranlux48>,
rng_cxx_read<RAN_NAMESPACE::ranlux48>,
+ rng_cxx_read_cstr<RAN_NAMESPACE::ranlux48>,
rng_cxx_write<RAN_NAMESPACE::ranlux48>,
+ rng_cxx_write_cstr<RAN_NAMESPACE::ranlux48>,
rng_cxx_entropy<RAN_NAMESPACE::ranlux48>,
RAN_NAMESPACE::ranlux48::min(),
RAN_NAMESPACE::ranlux48::max(),
@@ -350,7 +427,9 @@ const struct ssp_rng_type ssp_rng_random_device = {
rng_cxx_get<RAN_NAMESPACE::random_device>,
rng_cxx_discard<RAN_NAMESPACE::random_device>,
rng_cxx_read<RAN_NAMESPACE::random_device>,
+ rng_cxx_read_cstr<RAN_NAMESPACE::random_device>,
rng_cxx_write<RAN_NAMESPACE::random_device>,
+ rng_cxx_write_cstr<RAN_NAMESPACE::random_device>,
rng_cxx_entropy<RAN_NAMESPACE::random_device>,
RAN_NAMESPACE::random_device::min(),
RAN_NAMESPACE::random_device::max(),
@@ -390,7 +469,9 @@ const struct ssp_rng_type ssp_rng_threefry = {
rng_cxx_get<threefry_T>,
rng_cxx_discard<threefry_T>,
rng_cxx_read<threefry_T>,
+ rng_cxx_read_cstr<threefry_T>,
rng_cxx_write<threefry_T>,
+ rng_cxx_write_cstr<threefry_T>,
rng_cxx_entropy<threefry_T>,
threefry_T::min(),
threefry_T::max(),
@@ -407,7 +488,9 @@ const struct ssp_rng_type ssp_rng_aes = {
rng_cxx_get<aes_T>,
rng_cxx_discard<aes_T>,
rng_cxx_read<aes_T>,
+ rng_cxx_read_cstr<aes_T>,
rng_cxx_write<aes_T>,
+ rng_cxx_write_cstr<aes_T>,
rng_cxx_entropy<aes_T>,
aes_T::min(),
aes_T::max(),
@@ -643,12 +726,30 @@ ssp_rng_read(struct ssp_rng* rng, FILE* stream)
}
res_T
+ssp_rng_read_cstr(struct ssp_rng* rng, const char* cstr)
+{
+ if(!rng || !cstr) return RES_BAD_ARG;
+ return rng->type.read_cstr(rng->state, cstr);
+}
+
+res_T
ssp_rng_write(const struct ssp_rng* rng, FILE* stream)
{
if(!rng || !stream) return RES_BAD_ARG;
return rng->type.write(rng->state, stream);
}
+res_T
+ssp_rng_write_cstr
+ (const struct ssp_rng* rng,
+ char* buf,
+ const size_t bufsz,
+ size_t* len)
+{
+ if(!rng) return RES_BAD_ARG;
+ return rng->type.write_cstr(rng->state, buf, bufsz, len);
+}
+
double
ssp_rng_entropy(const struct ssp_rng* rng)
{
diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c
@@ -224,6 +224,13 @@ rng_bucket_read(void* data, FILE* file)
}
static res_T
+rng_bucket_read_cstr(void* data, const char* cstr)
+{
+ (void)data, (void)cstr;
+ return RES_BAD_OP;
+}
+
+static res_T
rng_bucket_write(const void* data, FILE* file)
{
(void)data, (void)file;
@@ -231,6 +238,17 @@ rng_bucket_write(const void* data, FILE* file)
}
static res_T
+rng_bucket_write_cstr
+ (const void* data,
+ char* buf,
+ const size_t bufsz,
+ size_t* len)
+{
+ (void)data, (void)buf, (void)bufsz, (void)len;
+ return RES_BAD_OP;
+}
+
+static res_T
rng_bucket_init(struct mem_allocator* allocator, void* data)
{
struct rng_bucket* rng = (struct rng_bucket*)data;
@@ -280,7 +298,9 @@ static const struct ssp_rng_type RNG_BUCKET_NULL = {
rng_bucket_get,
rng_bucket_discard,
rng_bucket_read,
+ rng_bucket_read_cstr,
rng_bucket_write,
+ rng_bucket_write_cstr,
rng_bucket_entropy,
INT_MAX, /* Min dummy value */
0, /* Max dummy value */
diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c
@@ -51,7 +51,9 @@ test_rng(const struct ssp_rng_type* type)
uint64_t datai1[NRAND];
double datad[NRAND];
float dataf[NRAND];
+ size_t len;
char buf[512];
+ char* cstr = NULL;
int i, j;
res_T r;
const char can_set = (type != &ssp_rng_random_device);
@@ -180,7 +182,7 @@ test_rng(const struct ssp_rng_type* type)
time_dump(&t0, TIME_SEC|TIME_MSEC|TIME_USEC, NULL, buf, sizeof(buf));
printf("1,000,000 random numbers in %s\n", buf);
- if (can_have_entropy) {
+ if(can_have_entropy) {
printf("Entropy for this implementation and system: %f\n",
ssp_rng_entropy(rng));
}
@@ -192,6 +194,15 @@ test_rng(const struct ssp_rng_type* type)
CHK(ssp_rng_write(NULL, stream) == RES_BAD_ARG);
CHK(ssp_rng_write(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP));
+ CHK(ssp_rng_write_cstr(NULL, NULL, 0, &len) == RES_BAD_ARG);
+ CHK(ssp_rng_write_cstr(rng, NULL, 0, NULL) == (can_rw ? RES_OK : RES_BAD_OP));
+ CHK(ssp_rng_write_cstr(rng, NULL, 0, &len) == (can_rw ? RES_OK : RES_BAD_OP));
+ cstr = mem_calloc(len+1, 1);
+ CHK(ssp_rng_write_cstr(rng, cstr, len+1, NULL) == (can_rw ? RES_OK : RES_BAD_OP));
+
+ /* Reserialize the RNG state */
+ CHK(ssp_rng_write(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP));
+
FOR_EACH(i, 0, NRAND)
datai0[i] = ssp_rng_get(rng);
@@ -200,14 +211,37 @@ test_rng(const struct ssp_rng_type* type)
CHK(ssp_rng_read(NULL, stream) == RES_BAD_ARG);
CHK(ssp_rng_read(rng, stream) == (can_rw ? RES_IO_ERR : RES_BAD_OP));
rewind(stream);
+
+ /* Read the first state of the stream */
CHK(ssp_rng_read(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP));
+ if(can_rw) {
+ FOR_EACH(i, 0, NRAND) {
+ uint64_t rn = ssp_rng_get(rng);
+ CHK(rn == datai0[i]);
+ }
+ }
+
+ /* Read the second state of the stream */
+ CHK(ssp_rng_read(rng, stream) == (can_rw ? RES_OK : RES_BAD_OP));
+ if(can_rw) {
+ FOR_EACH(i, 0, NRAND) {
+ uint64_t rn = ssp_rng_get(rng);
+ CHK(rn == datai0[i]);
+ }
+ }
- if (can_rw) {
+ /* Read the RNG state from an in memory buffer */
+ CHK(ssp_rng_read_cstr(NULL, cstr) == RES_BAD_ARG);
+ CHK(ssp_rng_read_cstr(rng, NULL) == RES_BAD_ARG);
+ CHK(ssp_rng_read_cstr(rng, cstr) == (can_rw ? RES_OK : RES_BAD_OP));
+ if(can_rw) {
FOR_EACH(i, 0, NRAND) {
uint64_t rn = ssp_rng_get(rng);
CHK(rn == datai0[i]);
}
}
+
+ mem_rm(cstr);
fclose(stream);
CHK(ssp_rng_ref_put(rng) == RES_OK);