Rework the odp_random_data() API to replace the use_entropy with an
explicit odp_random_kind parameter that controls the type of random
desired. Two new APIs are also introduced:

- odp_random_max_kind() returns the maximum kind of random data available

- odp_random_repeatable_data() permits applications to generate repeatable
  random sequences for testing purposes

Signed-off-by: Bill Fischofer <bill.fischo...@linaro.org>
---
Changes in v7:
- Clarify hierarchy of random kinds
- Expand on intended use of odp_random_repeatable_data()

Changes in v6:
- Add odp_random_max_kind() API instead of adding this to the
  odp_crypto_capability() API.
- Rename odp_random_seeded_data() to odp_random_repeatable_data()
- Merge API defs, implementation, and validation to preserve bisectability

Changes in v5:
- Change return type from int to int32_t for random APIs

Changes in v4:
- Normalize random API signatures with other ODP APIs
- Add new odp_random_seeded_data() API for repeatable random data generation
- Add additional tests for new odp_random_seeded_data() API
- Break out crypto section of User Guide to its own sub-document
- Add User Guide docuemntation for ODP random data API.

Changes in v3:
- Address commments by Petri
- Rename ODP_RAND_NORMAL to ODP_RANDOM_BASIC to avoid confusion with the
mathematical term "normal"

 include/odp/api/spec/random.h                   | 74 +++++++++++++++++++++++--
 platform/linux-generic/odp_crypto.c             | 50 +++++++++++++++--
 test/common_plat/validation/api/random/random.c | 54 +++++++++++++++++-
 test/common_plat/validation/api/random/random.h |  2 +
 4 files changed, 170 insertions(+), 10 deletions(-)

diff --git a/include/odp/api/spec/random.h b/include/odp/api/spec/random.h
index 00fa15b..6d770a6 100644
--- a/include/odp/api/spec/random.h
+++ b/include/odp/api/spec/random.h
@@ -24,18 +24,84 @@ extern "C" {
  */
 
 /**
+ * Random kind selector
+ *
+ * The kind of random denotes the statistical quality of the random data
+ * returned. Basic random simply appears uniformly distributed, Cryptographic
+ * random is statistically random and suitable for use by cryptographic
+ * functions. True random is generated from a hardware entropy source rather
+ * than an algorithm and is thus completely unpredictable. These form a
+ * hierarchy where higher quality data is presumably more costly to generate
+ * than lower quality data.
+ */
+typedef enum {
+       /** Basic random, presumably pseudo-random generated by SW */
+       ODP_RANDOM_BASIC,
+       /** Cryptographic quality random */
+       ODP_RANDOM_CRYPTO,
+       /** True random, generated from a HW entropy source */
+       ODP_RANDOM_TRUE,
+} odp_random_kind_t;
+
+/**
+ * Query random max kind
+ *
+ * Implementations support the returned max kind and all kinds weaker than it.
+ *
+ * @return kind The maximum odp_random_kind_t supported by this implementation
+ */
+odp_random_kind_t odp_random_max_kind(void);
+
+/**
  * Generate random byte data
  *
+ * The intent in supporting different kinds of random data is to allow
+ * tradeoffs between performance and the quality of random data needed. The
+ * assumption is that basic random is cheap while true random is relatively
+ * expensive in terms of time to generate, with cryptographic random being
+ * something in between. Implementations that support highly efficient true
+ * random are free to use this for all requested kinds. So it is always
+ * permissible to "upgrade" a random data request, but never to "downgrade"
+ * such requests.
+ *
  * @param[out]    buf   Output buffer
- * @param         size  Size of output buffer
- * @param use_entropy   Use entropy
+ * @param         len   Length of output buffer in bytes
+ * @param         kind  Specifies the type of random data required. Request
+ *                      is expected to fail if the implementation is unable to
+ *                      provide the requested type.
+ *
+ * @return Number of bytes written
+ * @retval <0 on failure
+ */
+int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind);
+
+/**
+ * Generate repeatable random byte data
+ *
+ * For testing purposes it is often useful to generate "random" sequences that
+ * are repeatable. This is accomplished by supplying a seed value that is used
+ * for pseudo-random data generation. The caller-provided seed value is
+ * updated for each call to continue the sequence. Restarting a series of
+ * calls with the same initial seed value will generate the same sequence of
+ * random test data.
+ *
+ * This function should be used only for testing purposes. Use
+ * odp_random_data() for production.
  *
- * @todo Define the implication of the use_entropy parameter
+ * @param[out]    buf  Output buffer
+ * @param         len  Length of output buffer in bytes
+ * @param         kind Specifies the type of random data required. Request
+ *                     will fail if the implementation is unable to provide
+ *                     repeatable random of the requested type. This is
+ *                     always true for true random and may be true for
+ *                     cryptographic random.
+ * @param[in,out] seed Seed value to use
  *
  * @return Number of bytes written
  * @retval <0 on failure
  */
-int32_t odp_random_data(uint8_t *buf, int32_t size, odp_bool_t use_entropy);
+int32_t odp_random_repeatable_data(uint8_t *buf, uint32_t len,
+                                  odp_random_kind_t kind, uint32_t *seed);
 
 /**
  * @}
diff --git a/platform/linux-generic/odp_crypto.c 
b/platform/linux-generic/odp_crypto.c
index 7e686ff..a731528 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
+#include <odp_posix_extensions.h>
 #include <odp/api/crypto.h>
 #include <odp_internal.h>
 #include <odp/api/atomic.h>
@@ -19,6 +20,7 @@
 #include <odp_packet_internal.h>
 
 #include <string.h>
+#include <stdlib.h>
 
 #include <openssl/des.h>
 #include <openssl/rand.h>
@@ -877,12 +879,50 @@ int odp_crypto_term_global(void)
        return rc;
 }
 
-int32_t
-odp_random_data(uint8_t *buf, int32_t len, odp_bool_t use_entropy ODP_UNUSED)
+odp_random_kind_t odp_random_max_kind(void)
 {
-       int32_t rc;
-       rc = RAND_bytes(buf, len);
-       return (1 == rc) ? len /*success*/: -1 /*failure*/;
+       return ODP_RANDOM_CRYPTO;
+}
+
+int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
+{
+       int rc;
+
+       switch (kind) {
+       case ODP_RANDOM_BASIC:
+               RAND_pseudo_bytes(buf, len);
+               return len;
+
+       case ODP_RANDOM_CRYPTO:
+               rc = RAND_bytes(buf, len);
+               return (1 == rc) ? (int)len /*success*/: -1 /*failure*/;
+
+       case ODP_RANDOM_TRUE:
+       default:
+               return -1;
+       }
+}
+
+int32_t odp_random_repeatable_data(uint8_t *buf, uint32_t len,
+                                  odp_random_kind_t kind, uint32_t *seed)
+{
+       union {
+               uint32_t rand_word;
+               uint8_t rand_byte[4];
+       } u;
+       uint32_t i = 0, j;
+
+       if (kind != ODP_RANDOM_BASIC)
+               return -1;
+
+       while (i < len) {
+               u.rand_word = rand_r(seed);
+
+               for (j = 0; j < 4 && i < len; j++, i++)
+                       *buf++ = u.rand_byte[j];
+       }
+
+       return len;
 }
 
 odp_crypto_compl_t odp_crypto_compl_from_event(odp_event_t ev)
diff --git a/test/common_plat/validation/api/random/random.c 
b/test/common_plat/validation/api/random/random.c
index 7572366..3537b2a 100644
--- a/test/common_plat/validation/api/random/random.c
+++ b/test/common_plat/validation/api/random/random.c
@@ -13,12 +13,64 @@ void random_test_get_size(void)
        int32_t ret;
        uint8_t buf[32];
 
-       ret = odp_random_data(buf, sizeof(buf), false);
+       ret = odp_random_data(buf, sizeof(buf), ODP_RANDOM_BASIC);
        CU_ASSERT(ret == sizeof(buf));
 }
 
+void random_test_kind(void)
+{
+       int32_t rc;
+       uint8_t buf[4096];
+       uint32_t buf_size = sizeof(buf);
+       odp_random_kind_t max_kind = odp_random_max_kind();
+
+       rc = odp_random_data(buf, buf_size, max_kind);
+       CU_ASSERT(rc > 0);
+
+       switch (max_kind) {
+       case ODP_RANDOM_BASIC:
+               rc = odp_random_data(buf, 4, ODP_RANDOM_CRYPTO);
+               CU_ASSERT(rc < 0);
+               /* Fall through */
+
+       case ODP_RANDOM_CRYPTO:
+               rc = odp_random_data(buf, 4, ODP_RANDOM_TRUE);
+               CU_ASSERT(rc < 0);
+               break;
+
+       default:
+               break;
+       }
+}
+
+void random_test_repeat(void)
+{
+       uint8_t buf1[1024];
+       uint8_t buf2[1024];
+       int32_t rc;
+       uint32_t seed1 = 12345897;
+       uint32_t seed2 = seed1;
+
+       rc = odp_random_repeatable_data(buf1, sizeof(buf1),
+                                       ODP_RANDOM_BASIC, &seed1);
+       CU_ASSERT(rc == sizeof(buf1));
+
+       rc = odp_random_repeatable_data(buf2, sizeof(buf2),
+                                       ODP_RANDOM_BASIC, &seed2);
+
+       CU_ASSERT(rc == sizeof(buf2));
+       CU_ASSERT(seed1 == seed2);
+       CU_ASSERT(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+
+       rc = odp_random_repeatable_data(buf1, sizeof(buf1),
+                                       ODP_RANDOM_TRUE, &seed1);
+       CU_ASSERT(rc < 0);
+}
+
 odp_testinfo_t random_suite[] = {
        ODP_TEST_INFO(random_test_get_size),
+       ODP_TEST_INFO(random_test_kind),
+       ODP_TEST_INFO(random_test_repeat),
        ODP_TEST_INFO_NULL,
 };
 
diff --git a/test/common_plat/validation/api/random/random.h 
b/test/common_plat/validation/api/random/random.h
index 26202cc..c4bca78 100644
--- a/test/common_plat/validation/api/random/random.h
+++ b/test/common_plat/validation/api/random/random.h
@@ -11,6 +11,8 @@
 
 /* test functions: */
 void random_test_get_size(void);
+void random_test_kind(void);
+void random_test_repeat(void);
 
 /* test arrays: */
 extern odp_testinfo_t random_suite[];
-- 
2.7.4

Reply via email to