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

View File

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

View File

@@ -20,38 +20,18 @@
#include "picokeys.h" #include "picokeys.h"
#include "hwrng.h" #include "hwrng.h"
#include "random.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 #define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)]; static uint8_t random_pool[256];
static mutex_t random_mutex;
static bool random_mutex_initialized = false;
void random_init(void) { void random_init(void) {
mutex_init(&random_mutex); hwrng_init(random_pool, sizeof(random_pool));
random_mutex_initialized = true;
hwrng_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
for (int i = 0; i < HWRNG_PRE_LOOP; i++) { 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 * Return pointer to random 32-byte
*/ */
@@ -60,17 +40,9 @@ const uint8_t *random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER) { if (len > MAX_RANDOM_BUFFER) {
return NULL; return NULL;
} }
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)]; static uint8_t return_word[MAX_RANDOM_BUFFER];
if (random_mutex_initialized) { if (random_fill_buffer(return_word, len) != 0) {
mutex_enter_blocking(&random_mutex); return NULL;
}
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);
} }
return (const uint8_t *) return_word; return (const uint8_t *) return_word;
} }
@@ -80,43 +52,25 @@ const uint8_t *random_bytes_get(size_t len) {
*/ */
int random_fill_iterator(void *arg, unsigned char *out, size_t out_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; 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; int ret = 0;
if (random_mutex_initialized) {
mutex_enter_blocking(&random_mutex);
}
while (out_len) { while (out_len) {
if (ctx && ctx->cancel) { if (ctx && ctx->cancel) {
ret = -1; ret = -1;
break; break;
} }
hwrng_wait_full(); size_t n = hwrng_read(out, out_len);
if (n == 0) {
n = RANDOM_BYTES_LENGTH - index; hwrng_task();
if (n > out_len) { continue;
n = (uint8_t)out_len;
} }
memcpy(out, ((unsigned char *) random_word) + index, n);
out += n; out += n;
out_len -= n; out_len -= n;
index += n; if (ctx) {
ctx->index = (uint8_t)((ctx->index + n) % RANDOM_BYTES_LENGTH);
if (index >= RANDOM_BYTES_LENGTH) {
index = 0;
hwrng_flush();
} }
} }
if (ctx) {
ctx->index = index;
}
if (random_mutex_initialized) {
mutex_exit(&random_mutex);
}
return ret; return ret;
} }