Refactor HWRNG to be less blocking.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2026-06-02 17:14:04 +02:00
parent 0245933224
commit 5fd26200ea
3 changed files with 98 additions and 123 deletions

View File

@@ -71,15 +71,13 @@ static int hwrng_mix_process(void) {
return 0;
}
PACK(
typedef struct hwrng_buf {
uint32_t *buf;
uint8_t head;
uint8_t tail;
uint8_t size;
unsigned int full : 1;
unsigned int empty : 1;
}) hwrng_buf_t;
uint8_t *buf;
size_t head;
size_t tail;
size_t size;
size_t count;
} hwrng_buf_t;
static mutex_t hwrng_mutex;
static bool hwrng_mutex_initialized = false;
@@ -96,49 +94,70 @@ static inline void hwrng_unlock(void) {
}
}
static void hwrng_buf_init(struct hwrng_buf *rb, uint32_t *p, uint8_t size) {
static void hwrng_buf_init(struct hwrng_buf *rb, uint8_t *p, size_t size) {
rb->buf = p;
rb->size = size;
rb->head = rb->tail = 0;
rb->full = 0;
rb->empty = 1;
rb->count = 0;
}
static void hwrng_buf_add(struct hwrng_buf *rb, uint32_t v) {
if (rb->full) {
return;
}
static size_t hwrng_buf_add(struct hwrng_buf *rb, const uint8_t *data, size_t len) {
size_t room = rb->size - rb->count;
size_t n = len < room ? len : room;
size_t tail = rb->tail;
size_t first = n;
uint8_t tail = rb->tail;
rb->buf[tail] = v;
tail++;
if (first > rb->size - tail) {
first = rb->size - tail;
}
if (first) {
memcpy(rb->buf + tail, data, first);
tail += first;
if (tail >= rb->size) {
tail = 0;
}
}
if (n > first) {
size_t second = n - first;
memcpy(rb->buf + tail, data + first, second);
tail += second;
}
rb->tail = tail;
rb->full = (rb->tail == rb->head);
rb->empty = 0;
rb->count += n;
return n;
}
static uint32_t hwrng_buf_del(struct hwrng_buf *rb) {
uint32_t v = 0;
if (rb->empty) {
return v;
}
static size_t hwrng_buf_del(struct hwrng_buf *rb, uint8_t *data, size_t len) {
size_t n = len < rb->count ? len : rb->count;
size_t head = rb->head;
size_t first = n;
uint8_t head = rb->head;
v = rb->buf[head];
head++;
if (first > rb->size - head) {
first = rb->size - head;
}
if (first) {
memcpy(data, rb->buf + head, first);
head += first;
if (head >= rb->size) {
head = 0;
}
rb->head = head;
if (rb->head == rb->tail) {
rb->empty = 1;
}
rb->full = 0;
if (n > first) {
size_t second = n - first;
memcpy(data + first, rb->buf + head, second);
head += second;
}
rb->head = head;
rb->count -= n;
return n;
}
return v;
static inline size_t hwrng_buf_space(const struct hwrng_buf *rb) {
return rb->size - rb->count;
}
static inline bool hwrng_buf_full(const struct hwrng_buf *rb) {
return rb->count == rb->size;
}
static struct hwrng_buf ring_buffer;
@@ -146,24 +165,15 @@ static struct hwrng_buf ring_buffer;
void *hwrng_task(void) {
struct hwrng_buf *rb = &ring_buffer;
int n;
hwrng_lock();
if ((n = hwrng_mix_process())) {
const uint32_t *vp = (const uint32_t *) &random_word;
for (int i = 0; i < n; i++) {
hwrng_buf_add(rb, *vp++);
if (rb->full) {
break;
}
}
if (hwrng_buf_space(rb) >= sizeof(random_word) && hwrng_mix_process()) {
hwrng_buf_add(rb, (const uint8_t *)&random_word, sizeof(random_word));
}
hwrng_unlock();
return NULL;
}
void hwrng_init(uint32_t *buf, uint8_t size) {
void hwrng_init(uint8_t *buf, size_t size) {
struct hwrng_buf *rb = &ring_buffer;
mutex_init(&hwrng_mutex);
@@ -175,28 +185,36 @@ void hwrng_init(uint32_t *buf, uint8_t size) {
hwrng_mix_init();
}
size_t hwrng_read(uint8_t *buf, size_t len) {
struct hwrng_buf *rb = &ring_buffer;
size_t n;
hwrng_lock();
n = hwrng_buf_del(rb, buf, len);
hwrng_unlock();
return n;
}
void hwrng_flush(void) {
struct hwrng_buf *rb = &ring_buffer;
hwrng_lock();
while (!rb->empty) {
hwrng_buf_del(rb);
}
rb->head = 0;
rb->tail = 0;
rb->count = 0;
hwrng_unlock();
}
uint32_t hwrng_get(void) {
struct hwrng_buf *rb = &ring_buffer;
uint32_t v;
uint32_t v = 0;
size_t offset = 0;
while (true) {
hwrng_lock();
if (!rb->empty) {
v = hwrng_buf_del(rb);
hwrng_unlock();
break;
}
hwrng_unlock();
while (offset < sizeof(v)) {
size_t n = hwrng_read(((uint8_t *)&v) + offset, sizeof(v) - offset);
if (n == 0) {
hwrng_task();
continue;
}
offset += n;
}
return v;
@@ -211,8 +229,9 @@ void hwrng_wait_full(void) {
#endif
while (true) {
hwrng_lock();
bool full = hwrng_buf_full(rb);
hwrng_unlock();
if (rb->full) {
if (full) {
break;
}
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)

View File

@@ -18,11 +18,13 @@
#ifndef _NEUG_H_
#define _NEUG_H_
#include <stdint.h>
#include <stddef.h>
void hwrng_init(uint32_t *buf, uint8_t size);
uint32_t hwrng_get(void);
void hwrng_init(uint8_t *buf, size_t size);
size_t hwrng_read(uint8_t *buf, size_t len);
void hwrng_flush(void);
void hwrng_wait_full(void);
void *hwrng_task(void);
uint32_t hwrng_get(void);
#endif

View File

@@ -20,38 +20,18 @@
#include "picokeys.h"
#include "hwrng.h"
#include "random.h"
#if defined(PICO_PLATFORM)
#include "pico/mutex.h"
#elif defined(ESP_PLATFORM)
#include "compat/esp_compat.h"
#else
#include "compat/queue.h"
#endif
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
static mutex_t random_mutex;
static bool random_mutex_initialized = false;
static uint8_t random_pool[256];
void random_init(void) {
mutex_init(&random_mutex);
random_mutex_initialized = true;
hwrng_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
hwrng_init(random_pool, sizeof(random_pool));
for (int i = 0; i < HWRNG_PRE_LOOP; i++) {
hwrng_get();
hwrng_task();
}
}
/*
* Free pointer to random 32-byte
*/
static void random_bytes_free(const uint8_t *p) {
(void) p;
memset(random_word, 0, RANDOM_BYTES_LENGTH);
hwrng_flush();
}
/*
* Return pointer to random 32-byte
*/
@@ -60,17 +40,9 @@ const uint8_t *random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER) {
return NULL;
}
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
if (random_mutex_initialized) {
mutex_enter_blocking(&random_mutex);
}
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
hwrng_wait_full();
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *) random_word);
}
if (random_mutex_initialized) {
mutex_exit(&random_mutex);
static uint8_t return_word[MAX_RANDOM_BUFFER];
if (random_fill_buffer(return_word, len) != 0) {
return NULL;
}
return (const uint8_t *) return_word;
}
@@ -80,41 +52,23 @@ const uint8_t *random_bytes_get(size_t len) {
*/
int random_fill_iterator(void *arg, unsigned char *out, size_t out_len) {
random_fill_iterator_ctx_t *ctx = (random_fill_iterator_ctx_t *) arg;
uint8_t index = ctx ? ctx->index : 0;
uint8_t n;
int ret = 0;
if (random_mutex_initialized) {
mutex_enter_blocking(&random_mutex);
}
while (out_len) {
if (ctx && ctx->cancel) {
ret = -1;
break;
}
hwrng_wait_full();
n = RANDOM_BYTES_LENGTH - index;
if (n > out_len) {
n = (uint8_t)out_len;
size_t n = hwrng_read(out, out_len);
if (n == 0) {
hwrng_task();
continue;
}
memcpy(out, ((unsigned char *) random_word) + index, n);
out += n;
out_len -= n;
index += n;
if (index >= RANDOM_BYTES_LENGTH) {
index = 0;
hwrng_flush();
}
}
if (ctx) {
ctx->index = index;
ctx->index = (uint8_t)((ctx->index + n) % RANDOM_BYTES_LENGTH);
}
if (random_mutex_initialized) {
mutex_exit(&random_mutex);
}
return ret;