CC3XX: Separate RNG, Entropy and TRNG modules
Follow the logic where RNG exposes methods to access
randomness, entropy exposes a SP800-90B compliant
entropy source and TRNG just deals with the hardware
regarded as a noise source.
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: I4c2aca6a262cd66ff69341322bf442755a41ef0b
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/CMakeLists.txt b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/CMakeLists.txt
index 806ce7e..e83a422 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/CMakeLists.txt
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/CMakeLists.txt
@@ -38,6 +38,7 @@
src/cc3xx_ecdh.c
src/cc3xx_dcu.c
src/cc3xx_trng.c
+ src/cc3xx_entropy.c
../common/cc3xx_stdlib.c
)
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_entropy.h b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_entropy.h
new file mode 100644
index 0000000..3dd60dd
--- /dev/null
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_entropy.h
@@ -0,0 +1,58 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CC3XX_ENTROPY_H
+#define CC3XX_ENTROPY_H
+
+#include "cc3xx_error.h"
+#include "cc3xx_trng.h"
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CC3XX_ENTROPY_SIZE (CC3XX_TRNG_SAMPLE_SIZE)
+
+/**
+ * @brief SP800-90B section 4.4 recommends two continuous health tests
+ * to be performed at startup and during normal operation of the
+ * noise source to verify the quality ot the entropy bits produced,
+ * namely the Repetition Count Test (4.4.1) and Adaptive Proportion
+ * Test (4.4.2)
+ *
+ * @param[in] enable Set to \a true to put the RNG entropy source in SP800-90B compatible
+ * mode, i.e. enable continuous health tests as recommended by SP800-90B
+ *
+ * @return cc3xx_err_t CC3XX_ERR_SUCCESS on success, or
+ * CC3XX_ERR_NOT_IMPLEMENTED in case the firmware is built
+ * without support for the continuous health tests, i.e.
+ * \a CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE is not
+ * set in the CC3XX configuration \a cc3xx_config.h
+ */
+cc3xx_err_t cc3xx_lowlevel_entropy_sp800_90b_mode(bool enable);
+
+/**
+ * @brief Requires an amount of entropy from the TRNG
+ *
+ * @param[out] entropy Buffer containing the requested entropy
+ * @param[in] entropy_len Size in bytes of the \p entropy buffer. Must be an
+ * integer multiple of \def CC3XX_ENTROPY_SIZE
+ *
+ * @return CC3XX_ERR_SUCCESS on success, another
+ * cc3xx_err_t on error.
+ */
+cc3xx_err_t cc3xx_lowlevel_entropy_get(uint32_t *entropy, size_t entropy_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CC3XX_ENTROPY_H */
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_rng.h b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_rng.h
index 77ab6a4..e895529 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_rng.h
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_rng.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2025, The TrustedFirmware-M Contributors. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -9,7 +9,6 @@
#define CC3XX_RNG_H
#include "cc3xx_error.h"
-#include "cc3xx_trng.h"
#include <stdint.h>
#include <stddef.h>
@@ -29,36 +28,6 @@
};
/**
- * @brief SP800-90B section 4.4 recommends two continuous health tests
- * to be performed at startup and during normal operation of the
- * noise source to verify the quality ot the entropy bits produced,
- * namely the Repetition Count Test (4.4.1) and Adaptive Proportion
- * Test (4.4.2)
- *
- * @param[in] enable Set to \a true to put the RNG entropy source in SP800-90B compatible
- * mode, i.e. enable continuous health tests as recommended by SP800-90B
- *
- * @return cc3xx_err_t CC3XX_ERR_SUCCESS on success, or
- * CC3XX_ERR_NOT_IMPLEMENTED in case the firmware is built
- * without support for the continuous health tests, i.e.
- * \a CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE is not
- * set in the CC3XX configuration \a cc3xx_config.h
- */
-cc3xx_err_t cc3xx_lowlevel_rng_sp800_90b_mode(bool enable);
-
-/**
- * @brief Requires an amount of entropy from the TRNG
- *
- * @param[out] entropy Buffer containing the requested entropy
- * @param[in] entropy_len Size in bytes of the \p entropy buffer. Must be an
- * integer multiple of \def CC3XX_RNG_ENTROPY_SIZE
- *
- * @return CC3XX_ERR_SUCCESS on success, another
- * cc3xx_err_t on error.
- */
-cc3xx_err_t cc3xx_lowlevel_rng_get_entropy(uint32_t *entropy, size_t entropy_len);
-
-/**
* @brief Get random bytes from the CC3XX TRNG.
*
* @note This function may take a variable amount of
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
index 5dd6427..b9fb87e 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
@@ -21,9 +21,9 @@
/**
* @brief Size in bytes of the generated entropy per each generation from the TRNG
- * It is equal to the sizeof(P_CC3XX->rng.ehr_data)
+ *
*/
-#define CC3XX_RNG_ENTROPY_SIZE (sizeof(P_CC3XX->rng.ehr_data))
+#define CC3XX_TRNG_SAMPLE_SIZE (sizeof(P_CC3XX->rng.ehr_data))
#ifndef __PACKED_ENUM
#define __PACKED_ENUM enum __attribute__((packed))
@@ -94,17 +94,18 @@
void cc3xx_lowlevel_trng_set_hw_test_bypass(bool bypass_autocorr, bool bypass_crngt, bool bypass_vnc);
/**
- * @brief Reads the entropy out of the TRNG
+ * @brief Reads the sample out of the TRNG
*
* @param[out] buf Output buffer, word aligned, into which the entropy is read
* @param[in] word_count Size in words of the \p buf output buffer, must be equal to
- * the number of words of P_CC3XX->rng.ehr_data
+ * the number of words of P_CC3XX->rng.ehr_data, i.e. CC3XX_TRNG_SAMPLE_SIZE
+ * when expressed in bytes
*
* @return cc3xx_err_t CC3XX_ERR_SUCCESS on success, CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS in
* case errors have been detected on each generation. The maximum
* number of generations is controlled by CC3XX_CONFIG_RNG_MAX_ATTEMPTS
*/
-cc3xx_err_t cc3xx_lowlevel_trng_get_entropy(uint32_t *buf, size_t word_count);
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count);
/**
* @brief Initialises the TRNG before a call to \a cc3xx_lowlevel_trng_get_entropy
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_entropy.c b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_entropy.c
new file mode 100644
index 0000000..fb70f66
--- /dev/null
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_entropy.c
@@ -0,0 +1,261 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CC3XX_CONFIG_FILE
+#include "cc3xx_config.h"
+#else
+#include CC3XX_CONFIG_FILE
+#endif
+
+#include "cc3xx_error.h"
+
+#ifdef CC3XX_CONFIG_RNG_EXTERNAL_TRNG
+#include "cc3xx_rng_external_trng.h"
+#else
+#include "cc3xx_trng.h"
+#endif /* CC3XX_CONFIG_RNG_EXTERNAL_TRNG */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "fatal_error.h"
+
+#ifdef CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT
+int32_t count_zero_bits_external(uint8_t *, size_t, uint32_t *);
+#endif /* CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT */
+
+/* Specific defines required to enable Continuous testing as per NIST SP800-90B */
+#define BYTES_TO_BITS(x) ((x)*8)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/**
+ * @brief Window size (W) for the Adaptive Proportion Test in SP800-90B section 4.4.2
+ *
+ * @note For binary entropy sources this is fixed to 1024 bits
+ *
+ */
+#define SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE (1024UL)
+
+/**
+ * @brief Cutoff rate (C) for the Adaptive Proportion Test in SP800-90B section 4.4.2
+ *
+ * @note This is computed using the formula:
+ *
+ * CRITBINOM(W, power(2,(-H)), 1-a) with W = 1024, a = 2^(-40), H = 0.5 bits/sample
+ *
+ * The cutoff rate is chosen such that the probability of observing B identical
+ * samples in an observation window of length W is Pr{B >= C} < a
+ */
+#define SP800_90B_ADAPTIVE_PROPORTION_CUTOFF_RATE (821UL)
+
+/**
+ * @brief Cutoff rate (C) for the Repetition Count Test in SP800-90B section 4.4.1
+ *
+ * @note This is computed using the formula:
+ *
+ * 1 + ceil(-log(2,a) / H) with a = 2^(-40), H = 0.5 bits/sample a
+ *
+ * The cutoff rate is chosen such that C is the smallest integer satisfying
+ * a >= 2^(-H * (C-1)), i.e. the probability of getting C consecutive identical
+ * samples is at most a
+ */
+#define SP800_90B_REPETITION_COUNT_CUTOFF_RATE (81UL)
+
+/* Static context of the TRNG continuous health tests */
+static struct health_tests_ctx_t {
+ size_t total_bits_count; /*!< Number of total bits observed for the Adaptive Proportion Test window */
+ size_t number_of_0s; /*!< Number of zeros observed in the Adaptive Proportion Test window */
+ size_t number_of_contiguous_0s; /*!< Number of contiguous zeros observed in the Repetition Count Test */
+ size_t number_of_contiguous_1s; /*!< Number of contiguous ones observed in the Repetition Count Test */
+ bool continuous; /*!< Continous Health tests enabled, i.e. both Adaptive Proportion and Repetition Count */
+ bool startup; /*!< Indicates whether a full startup test is performed on next call to get_entropy */
+} g_entropy_tests = {0};
+
+/* See https://en.wikipedia.org/wiki/Hamming_weight */
+static size_t popcount32(uint32_t x)
+{
+ const uint32_t m1 = 0x55555555; /* binary: 0101 ... */
+ const uint32_t m2 = 0x33333333; /* binary: 00110011 ... */
+ const uint32_t m4 = 0x0f0f0f0f; /* binary: 4 zeros, 4 ones ... */
+ const uint32_t h01 = 0x01010101; /* Sum of 256 to the power of 0, 1, 2, 3 ... */
+ x -= (x >> 1) & m1; /* put count of each 2 bits into those 2 bits */
+ x = (x & m2) + ((x >> 2) & m2); /* put count of each 4 bits into those 4 bits */
+ x = (x + (x >> 4)) & m4; /* put count of each 8 bits into those 8 bits */
+ return (x * h01) >> 24; /* returns left 8 bits of x + (x<<8) + (x<<16) + ... */
+}
+
+static cc3xx_err_t count_zero_bits(uint8_t *buf, size_t buf_len, uint32_t *zero_count)
+{
+#ifndef CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT
+ assert((((uintptr_t) buf & 0x3) == 0) && ((buf_len & 0x3) == 0));
+
+ for (size_t i = 0; i < buf_len / sizeof(uint32_t); i++) {
+ *zero_count += BYTES_TO_BITS(sizeof(uint32_t)) - popcount32(((uint32_t *)buf)[i]);
+ }
+ return CC3XX_ERR_SUCCESS;
+#else
+ return count_zero_bits_external(buf, buf_len, zero_count);
+#endif /* CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT */
+}
+
+/* SP800-90B section 4.4.1 */
+static cc3xx_err_t repetition_count_test(const uint32_t *buf, size_t buf_size, size_t *number_of_contiguous_0s, size_t *number_of_contiguous_1s)
+{
+ for (size_t idx = 0; idx < buf_size; idx++) {
+ uint8_t byte = ((uint8_t *)buf)[idx];
+ for (size_t bit = 0; bit < 8; bit++) {
+ if ((byte >> bit) & 0x01) {
+ (*number_of_contiguous_1s)++;
+ *number_of_contiguous_0s = 0;
+ } else {
+ (*number_of_contiguous_0s)++;
+ *number_of_contiguous_1s = 0;
+ }
+ if (((*number_of_contiguous_0s) == SP800_90B_REPETITION_COUNT_CUTOFF_RATE) ||
+ ((*number_of_contiguous_1s) == SP800_90B_REPETITION_COUNT_CUTOFF_RATE)) {
+ FATAL_ERR(CC3XX_ERR_RNG_SP800_90B_REPETITION_COUNT_TEST_FAIL);
+ return CC3XX_ERR_RNG_SP800_90B_REPETITION_COUNT_TEST_FAIL;
+ }
+ }
+ }
+
+ return CC3XX_ERR_SUCCESS;
+}
+
+/* SP800-90B section 4.4.2 */
+static cc3xx_err_t adaptive_proportion_test(const uint32_t *buf, size_t buf_size, size_t *total_bits_count, size_t *number_of_0s)
+{
+ while (buf_size) {
+
+ /* Compute the words that we still have to count until the end of the window */
+ const size_t words_left_to_count =
+ (SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE - *total_bits_count) / BYTES_TO_BITS(sizeof(uint32_t));
+ const size_t bytes_left_to_count = words_left_to_count * sizeof(uint32_t);
+ const size_t counted_bytes = MIN(buf_size, bytes_left_to_count);
+
+ count_zero_bits((uint8_t *)buf, counted_bytes, (uint32_t *)number_of_0s);
+
+ *total_bits_count += BYTES_TO_BITS(counted_bytes);
+ buf_size -= counted_bytes;
+
+ if (*total_bits_count == SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE) {
+ if ((*number_of_0s >= SP800_90B_ADAPTIVE_PROPORTION_CUTOFF_RATE) ||
+ ((SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE - *number_of_0s) >=
+ SP800_90B_ADAPTIVE_PROPORTION_CUTOFF_RATE)) {
+ FATAL_ERR(CC3XX_ERR_RNG_SP800_90B_ADAPTIVE_PROPORTION_TEST_FAIL);
+ return CC3XX_ERR_RNG_SP800_90B_ADAPTIVE_PROPORTION_TEST_FAIL;
+ } else {
+ *number_of_0s = 0;
+ *total_bits_count = 0;
+ }
+ }
+
+ /* Move the buf pointer in case we still have to process bits from this entropy collection */
+ buf += counted_bytes / sizeof(uint32_t);
+ }
+
+ return CC3XX_ERR_SUCCESS;
+}
+
+/* SP800-90B section 4.4 */
+static cc3xx_err_t continuous_health_test(const uint32_t *buf, size_t buf_size, struct health_tests_ctx_t *ctx)
+{
+ cc3xx_err_t err = repetition_count_test(
+ buf, buf_size, &(ctx->number_of_contiguous_0s), &(ctx->number_of_contiguous_1s));
+
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ return adaptive_proportion_test(buf, buf_size, &(ctx->total_bits_count), &(ctx->number_of_0s));
+}
+
+/**
+ * @brief To be performed on the first call to get_entropy(),
+ * after the cc3xx_lowlevel_trng_init() is completed
+ *
+ * @return cc3xx_err_t
+ */
+static cc3xx_err_t startup_test(size_t entropy_byte_size)
+{
+ assert(entropy_byte_size == CC3XX_TRNG_SAMPLE_SIZE);
+
+ cc3xx_err_t err;
+ uint32_t random_bits[entropy_byte_size / sizeof(uint32_t)];
+
+ /* Collects 528 sample bytes on startup for testing */
+ for (size_t i = 0; i < 22; i++) {
+ err = cc3xx_lowlevel_trng_get_sample(random_bits, entropy_byte_size / sizeof(uint32_t));
+ if (err != CC3XX_ERR_SUCCESS) {
+ break;
+ }
+ }
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_lowlevel_entropy_sp800_90b_mode(bool enable)
+{
+ if (enable) {
+ g_entropy_tests = (struct health_tests_ctx_t){.startup = true};
+ } else {
+ g_entropy_tests = (struct health_tests_ctx_t){0};
+ }
+
+ cc3xx_lowlevel_trng_sp800_90b_mode(enable);
+
+ return CC3XX_ERR_SUCCESS;
+}
+
+cc3xx_err_t cc3xx_lowlevel_entropy_get(uint32_t *entropy, size_t entropy_len)
+{
+ cc3xx_err_t err;
+ size_t num_words = 0;
+
+ assert((entropy_len % CC3XX_TRNG_SAMPLE_SIZE) == 0);
+
+ err = cc3xx_lowlevel_trng_validate_config();
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+
+ cc3xx_lowlevel_trng_init();
+
+ if (g_entropy_tests.startup) {
+ err = startup_test(CC3XX_TRNG_SAMPLE_SIZE);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto cleanup;
+ }
+ g_entropy_tests.startup = false;
+ }
+
+ for (size_t i = 0; i < entropy_len / CC3XX_TRNG_SAMPLE_SIZE; i++) {
+
+ err = cc3xx_lowlevel_trng_get_sample(&entropy[num_words], CC3XX_TRNG_SAMPLE_SIZE / sizeof(uint32_t));
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto cleanup;
+ }
+
+ if (g_entropy_tests.continuous) {
+ err = continuous_health_test(
+ &entropy[num_words], CC3XX_TRNG_SAMPLE_SIZE, &g_entropy_tests);
+ if (err != CC3XX_ERR_SUCCESS) {
+ goto cleanup;
+ }
+ }
+
+ num_words += CC3XX_TRNG_SAMPLE_SIZE / sizeof(uint32_t);
+ }
+
+cleanup:
+ cc3xx_lowlevel_trng_finish();
+
+ return err;
+}
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_rng.c b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_rng.c
index 50139a3..f3fb2d7 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_rng.c
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_rng.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2025, The TrustedFirmware-M Contributors. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -16,6 +16,7 @@
#include "cc3xx_error.h"
#include "cc3xx_dev.h"
#include "cc3xx_stdlib.h"
+#include "cc3xx_entropy.h"
#if defined(CC3XX_CONFIG_RNG_DRBG_HMAC)
#include "cc3xx_drbg_hmac.h"
#elif defined(CC3XX_CONFIG_RNG_DRBG_HASH)
@@ -32,203 +33,7 @@
#include "fatal_error.h"
-#ifdef CC3XX_CONFIG_RNG_EXTERNAL_TRNG
-#include "cc3xx_rng_external_trng.h"
-#endif /* CC3XX_CONFIG_RNG_EXTERNAL_TRNG */
-
-#ifdef CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT
-int32_t count_zero_bits_external(uint8_t *, size_t, uint32_t *);
-#endif /* CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT */
-
-/* Specific defines required to enable Continuous testing as per NIST SP800-90B */
-#define BYTES_TO_BITS(x) ((x)*8)
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-/**
- * @brief Window size (W) for the Adaptive Proportion Test in SP800-90B section 4.4.2
- *
- * @note For binary entropy sources this is fixed to 1024 bits
- *
- */
-#define SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE (1024UL)
-
-/**
- * @brief Cutoff rate (C) for the Adaptive Proportion Test in SP800-90B section 4.4.2
- *
- * @note This is computed using the formula:
- *
- * CRITBINOM(W, power(2,(-H)), 1-a) with W = 1024, a = 2^(-40), H = 0.5 bits/sample
- *
- * The cutoff rate is chosen such that the probability of observing B identical
- * samples in an observation window of length W is Pr{B >= C} < a
- */
-#define SP800_90B_ADAPTIVE_PROPORTION_CUTOFF_RATE (821UL)
-
-/**
- * @brief Cutoff rate (C) for the Repetition Count Test in SP800-90B section 4.4.1
- *
- * @note This is computed using the formula:
- *
- * 1 + ceil(-log(2,a) / H) with a = 2^(-40), H = 0.5 bits/sample a
- *
- * The cutoff rate is chosen such that C is the smallest integer satisfying
- * a >= 2^(-H * (C-1)), i.e. the probability of getting C consecutive identical
- * samples is at most a
- */
-#define SP800_90B_REPETITION_COUNT_CUTOFF_RATE (81UL)
-
#ifdef CC3XX_CONFIG_RNG_ENABLE
-#if defined(CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE)
-/* Static context of the TRNG continuous health tests */
-static struct health_tests_ctx_t {
- size_t total_bits_count; /*!< Number of total bits observed for the Adaptive Proportion Test window */
- size_t number_of_0s; /*!< Number of zeros observed in the Adaptive Proportion Test window */
- size_t number_of_contiguous_0s; /*!< Number of contiguous zeros observed in the Repetition Count Test */
- size_t number_of_contiguous_1s; /*!< Number of contiguous ones observed in the Repetition Count Test */
- bool continuous; /*!< Continous Health tests enabled, i.e. both Adaptive Proportion and Repetition Count */
- bool startup; /*!< Indicates whether a full startup test is performed on next call to get_entropy */
-} g_trng_tests = {0};
-
-/* See https://en.wikipedia.org/wiki/Hamming_weight */
-static size_t popcount32(uint32_t x)
-{
- const uint32_t m1 = 0x55555555; /* binary: 0101 ... */
- const uint32_t m2 = 0x33333333; /* binary: 00110011 ... */
- const uint32_t m4 = 0x0f0f0f0f; /* binary: 4 zeros, 4 ones ... */
- const uint32_t h01 = 0x01010101; /* Sum of 256 to the power of 0, 1, 2, 3 ... */
- x -= (x >> 1) & m1; /* put count of each 2 bits into those 2 bits */
- x = (x & m2) + ((x >> 2) & m2); /* put count of each 4 bits into those 4 bits */
- x = (x + (x >> 4)) & m4; /* put count of each 8 bits into those 8 bits */
- return (x * h01) >> 24; /* returns left 8 bits of x + (x<<8) + (x<<16) + ... */
-}
-
-static cc3xx_err_t count_zero_bits(uint8_t *buf, size_t buf_len, uint32_t *zero_count)
-{
-#ifndef CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT
- assert((((uintptr_t) buf & 0x3) == 0) && ((buf_len & 0x3) == 0));
-
- for (size_t i = 0; i < buf_len / sizeof(uint32_t); i++) {
- *zero_count += BYTES_TO_BITS(sizeof(uint32_t)) - popcount32(((uint32_t *)buf)[i]);
- }
- return CC3XX_ERR_SUCCESS;
-#else
- return count_zero_bits_external(buf, buf_len, zero_count);
-#endif /* CC3XX_CONFIG_RNG_EXTERNAL_ZERO_COUNT */
-}
-
-/* SP800-90B section 4.4.1 */
-static cc3xx_err_t repetition_count_test(const uint32_t *buf, size_t buf_size, size_t *number_of_contiguous_0s, size_t *number_of_contiguous_1s)
-{
- for (size_t idx = 0; idx < buf_size; idx++) {
- uint8_t byte = ((uint8_t *)buf)[idx];
- for (size_t bit = 0; bit < 8; bit++) {
- if ((byte >> bit) & 0x01) {
- (*number_of_contiguous_1s)++;
- *number_of_contiguous_0s = 0;
- } else {
- (*number_of_contiguous_0s)++;
- *number_of_contiguous_1s = 0;
- }
- if (((*number_of_contiguous_0s) == SP800_90B_REPETITION_COUNT_CUTOFF_RATE) ||
- ((*number_of_contiguous_1s) == SP800_90B_REPETITION_COUNT_CUTOFF_RATE)) {
- FATAL_ERR(CC3XX_ERR_RNG_SP800_90B_REPETITION_COUNT_TEST_FAIL);
- return CC3XX_ERR_RNG_SP800_90B_REPETITION_COUNT_TEST_FAIL;
- }
- }
- }
-
- return CC3XX_ERR_SUCCESS;
-}
-
-/* SP800-90B section 4.4.2 */
-static cc3xx_err_t adaptive_proportion_test(const uint32_t *buf, size_t buf_size, size_t *total_bits_count, size_t *number_of_0s)
-{
- while (buf_size) {
-
- /* Compute the words that we still have to count until the end of the window */
- const size_t words_left_to_count =
- (SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE - *total_bits_count) / BYTES_TO_BITS(sizeof(uint32_t));
- const size_t bytes_left_to_count = words_left_to_count * sizeof(uint32_t);
- const size_t counted_bytes = MIN(buf_size, bytes_left_to_count);
-
- count_zero_bits((uint8_t *)buf, counted_bytes, (uint32_t *)number_of_0s);
-
- *total_bits_count += BYTES_TO_BITS(counted_bytes);
- buf_size -= counted_bytes;
-
- if (*total_bits_count == SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE) {
- if ((*number_of_0s >= SP800_90B_ADAPTIVE_PROPORTION_CUTOFF_RATE) ||
- ((SP800_90B_ADAPTIVE_PROPORTION_WINDOW_SIZE - *number_of_0s) >=
- SP800_90B_ADAPTIVE_PROPORTION_CUTOFF_RATE)) {
- FATAL_ERR(CC3XX_ERR_RNG_SP800_90B_ADAPTIVE_PROPORTION_TEST_FAIL);
- return CC3XX_ERR_RNG_SP800_90B_ADAPTIVE_PROPORTION_TEST_FAIL;
- } else {
- *number_of_0s = 0;
- *total_bits_count = 0;
- }
- }
-
- /* Move the buf pointer in case we still have to process bits from this entropy collection */
- buf += counted_bytes / sizeof(uint32_t);
- }
-
- return CC3XX_ERR_SUCCESS;
-}
-
-/* SP800-90B section 4.4 */
-static cc3xx_err_t continuous_health_test(const uint32_t *buf, size_t buf_size, struct health_tests_ctx_t *ctx)
-{
- cc3xx_err_t err = repetition_count_test(
- buf, buf_size, &(ctx->number_of_contiguous_0s), &(ctx->number_of_contiguous_1s));
-
- if (err != CC3XX_ERR_SUCCESS) {
- return err;
- }
-
- return adaptive_proportion_test(buf, buf_size, &(ctx->total_bits_count), &(ctx->number_of_0s));
-}
-
-/**
- * @brief To be performed on the first call to get_entropy(),
- * after the cc3xx_lowlevel_trng_init() is completed
- *
- * @return cc3xx_err_t
- */
-static cc3xx_err_t startup_test(size_t entropy_byte_size)
-{
- assert(entropy_byte_size == sizeof(P_CC3XX->rng.ehr_data));
-
- cc3xx_err_t err;
- uint32_t random_bits[entropy_byte_size / sizeof(uint32_t)];
-
- /* Collects 528 random bytes on startup for testing */
- for (size_t i = 0; i < 22; i++) {
- err = trng_get_random(random_bits, entropy_byte_size / sizeof(uint32_t));
- if (err != CC3XX_ERR_SUCCESS) {
- break;
- }
- }
-
- return err;
-}
-#endif /* CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE */
-
-cc3xx_err_t cc3xx_lowlevel_rng_sp800_90b_mode(bool enable)
-{
-#if defined(CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE)
- if (enable) {
- g_trng_tests = (struct health_tests_ctx_t){.startup = true};
- } else {
- g_trng_tests = (struct health_tests_ctx_t){0};
- }
-
- cc3xx_lowlevel_trng_sp800_90b_mode(enable);
-
- return CC3XX_ERR_SUCCESS;
-#else
- return CC3XX_ERR_NOT_IMPLEMENTED;
-#endif
-}
/* Define function pointers to generically access DRBG functionalities */
#if defined(CC3XX_CONFIG_RNG_DRBG_HMAC)
@@ -290,7 +95,7 @@
if (!lfsr->seed_done) {
cc3xx_err_t err;
do {
- err = cc3xx_lowlevel_rng_get_entropy(lfsr->entropy, sizeof(lfsr->entropy));
+ err = cc3xx_lowlevel_entropy_get(lfsr->entropy, sizeof(lfsr->entropy));
} while (err != CC3XX_ERR_SUCCESS);
lfsr->seed_done = true;
@@ -324,11 +129,10 @@
if (!g_drbg.seed_done) {
- /* Get a 24-byte seed from the TRNG */
- err = cc3xx_lowlevel_rng_get_entropy(entropy, sizeof(entropy));
- if (err != CC3XX_ERR_SUCCESS) {
- return err;
- }
+ /* Get 24 bytes of entropy */
+ do {
+ err = cc3xx_lowlevel_entropy_get(entropy, sizeof(entropy));
+ } while (err != CC3XX_ERR_SUCCESS);
/* Call the seeding API of the desired drbg */
err = g_drbg.init(&g_drbg.state,
@@ -346,11 +150,10 @@
/* Add re-seeding capabilities */
if (g_drbg.state.reseed_counter == UINT32_MAX) {
- /* Get a 24-byte seed from the TRNG */
- err = cc3xx_lowlevel_rng_get_entropy(entropy, sizeof(entropy));
- if (err != CC3XX_ERR_SUCCESS) {
- return err;
- }
+ /* Get 24 bytes of entropy */
+ do {
+ err = cc3xx_lowlevel_entropy_get(entropy, sizeof(entropy));
+ } while (err != CC3XX_ERR_SUCCESS);
err = g_drbg.reseed(&g_drbg.state,
(const uint8_t *)entropy, sizeof(entropy), NULL, 0);
@@ -370,61 +173,6 @@
return err;
}
-cc3xx_err_t cc3xx_lowlevel_rng_get_entropy(uint32_t *entropy, size_t entropy_len)
-{
- cc3xx_err_t err;
- size_t num_words = 0;
-
- assert((entropy_len % sizeof(P_CC3XX->rng.ehr_data)) == 0);
-
- err = cc3xx_lowlevel_trng_validate_config();
- if (err != CC3XX_ERR_SUCCESS) {
- return err;
- }
-
- cc3xx_lowlevel_trng_init();
-
- /* This is guarded by the continuous tests define because that is the
- * only type of testing that is being implemented by the startup_test
- * function although the spec allows for startup tests to be extended
- * by vendors if required
- */
-#if defined(CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE)
- if (g_trng_tests.startup) {
- err = startup_test(sizeof(P_CC3XX->rng.ehr_data));
- if (err != CC3XX_ERR_SUCCESS) {
- goto cleanup;
- }
- g_trng_tests.startup = false;
- }
-#endif /* CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE */
-
- for (size_t i = 0; i < entropy_len / sizeof(P_CC3XX->rng.ehr_data); i++) {
-
- err = cc3xx_lowlevel_trng_get_entropy(&entropy[num_words], sizeof(P_CC3XX->rng.ehr_data) / sizeof(uint32_t));
- if (err != CC3XX_ERR_SUCCESS) {
- goto cleanup;
- }
-
-#if defined(CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE)
- if (g_trng_tests.continuous) {
- err = continuous_health_test(
- (uint8_t *)&entropy[num_words], sizeof(P_CC3XX->rng.ehr_data), &g_trng_tests);
- if (err != CC3XX_ERR_SUCCESS) {
- goto cleanup;
- }
- }
-#endif /* CC3XX_CONFIG_RNG_CONTINUOUS_HEALTH_TESTS_ENABLE */
-
- num_words += sizeof(P_CC3XX->rng.ehr_data) / sizeof(uint32_t);
- }
-
-cleanup:
- cc3xx_lowlevel_trng_finish();
-
- return err;
-}
-
cc3xx_err_t cc3xx_lowlevel_rng_get_random(uint8_t *buf, size_t length,
enum cc3xx_rng_quality_t quality)
{
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
index cd4f701..8766e06 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
@@ -140,15 +140,15 @@
return CC3XX_ERR_SUCCESS;
}
-cc3xx_err_t cc3xx_lowlevel_trng_get_entropy(uint32_t *buf, size_t word_count)
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count)
{
uint32_t attempt_count = 0;
uint32_t idx;
assert(word_count == sizeof(P_CC3XX->rng.ehr_data) / sizeof(uint32_t));
- /* Wait until the RNG has finished. Any status other than 0x1 indicates
- * that either the RNG hasn't finished or a statistical test has been
+ /* Wait until the TRNG has finished. Any status other than 0x1 indicates
+ * that either the TRNG hasn't finished or a statistical test has been
* failed.
*/
do {
diff --git a/platform/ext/target/arm/drivers/cc3xx/psa_driver_api/src/cc3xx_psa_entropy.c b/platform/ext/target/arm/drivers/cc3xx/psa_driver_api/src/cc3xx_psa_entropy.c
index 41ef966..0e0a82a 100644
--- a/platform/ext/target/arm/drivers/cc3xx/psa_driver_api/src/cc3xx_psa_entropy.c
+++ b/platform/ext/target/arm/drivers/cc3xx/psa_driver_api/src/cc3xx_psa_entropy.c
@@ -15,7 +15,7 @@
#include <string.h>
#include "cc3xx_psa_entropy.h"
-#include "cc3xx_rng.h"
+#include "cc3xx_entropy.h"
#include "cc3xx_misc.h"
/** @defgroup psa_entropy PSA driver entry points for entropy collection
@@ -31,7 +31,7 @@
{
cc3xx_err_t err;
/* Integer multiple of entropy size*/
- const size_t int_mult = (output_size / CC3XX_RNG_ENTROPY_SIZE) * CC3XX_RNG_ENTROPY_SIZE;
+ const size_t int_mult = (output_size / CC3XX_ENTROPY_SIZE) * CC3XX_ENTROPY_SIZE;
CC3XX_ASSERT(output != NULL);
CC3XX_ASSERT(output_size != 0);
@@ -40,16 +40,16 @@
*estimate_bits = 0;
}
- /* Get a multiple of CC3XX_RNG_ENTROPY_SIZE bytes of entropy */
- err = cc3xx_lowlevel_rng_get_entropy((uint32_t *)output, int_mult);
+ /* Get a multiple of CC3XX_ENTROPY_SIZE bytes of entropy */
+ err = cc3xx_lowlevel_entropy_get((uint32_t *)output, int_mult);
if (err != CC3XX_ERR_SUCCESS) {
return cc3xx_to_psa_err(err);
}
- if ((output_size % CC3XX_RNG_ENTROPY_SIZE) != 0) {
- uint32_t last[CC3XX_RNG_ENTROPY_SIZE / sizeof(uint32_t)];
- err = cc3xx_lowlevel_rng_get_entropy(last, sizeof(last));
+ if ((output_size % CC3XX_ENTROPY_SIZE) != 0) {
+ uint32_t last[CC3XX_ENTROPY_SIZE / sizeof(uint32_t)];
+ err = cc3xx_lowlevel_entropy_get(last, sizeof(last));
if (err != CC3XX_ERR_SUCCESS) {
return cc3xx_to_psa_err(err);
}