ASCON Suite
Porting the TRNG to new platforms

Applications should use the PRNG API to get random data. In particular, the ascon_random() function provides a quick method to get random data that has a uniform spread of entropy and has had any vendor watermarks or bias removed.

The functions in the backend TRNG API are how the library harvests entropy from the system, but that entropy should not be used directly by applications. It may be of poor quality or the CPU vendor may be untrustworthy.

The rest of this page is only of interest to people who want to port the library to a new microcontroller that has a built-in random number generator peripheral.

Backends

The library contains several TRNG backends for interfacing to the system's random number generator in the src/random subdirectory:

BackendPlatforms</td
dev-randomLinux, FreeBSD, OpenBSD, and other Unix-like systems with a /dev/urandom device.
dueArudino Due / SAM3X8E
espESP8266 and ESP32 modules
noneDefault if the platform is not recognised
stm32STM32 platforms with the HAL_RNG_GenerateRandomNumber() function
windowsWindows systems using the CryptGenRandom() function
zephyrZephyr RTOS systems with either sys_csrand_get() or bt_rand() configured

The file ascon-select-trng.h contains #ifdef's to select the specific backend. You will need to modify this file when adding a new backend.

The "dev-random" backend will use the getrandom() or genentropy() functions instead of /dev/urandom, if one of those functions is present on the system.

On Arduino systems, the "none" backend will harvest a very small amount of entropy from the millis() and micros() functions but the result will not be very good against a determined adversary.

Patches welcome to add support for TRNG peripherals on other microcontrollers.

Porting to a new platform

There are two separate TRNG API's declared in ascon-trng.h.

The first API is the function ascon_trng_generate() which generates a buffer of random bytes and returns them to the caller. This is called from the PRNG API in various places to request 256 bits of random data to initialize or re-seed the PRNG.

The following example is from the "esp" backend, which uses the Espressif SDK function esp_random() to acquire 32-bit random values:

int ascon_trng_generate(unsigned char *out, size_t outlen)
{
uint32_t x;
while (outlen >= sizeof(x)) {
x = esp_random();
memcpy(out, &x, sizeof(x));
out += sizeof(x);
outlen -= sizeof(x);
}
if (outlen > 0) {
x = esp_random();
memcpy(out, &x, outlen);
}
return 1; /* Assume that it works */
}
int ascon_trng_generate(unsigned char *out, size_t outlen)
Generates a buffer of bytes from the system TRNG source.

The ascon_trng_generate() function should return non-zero if the backend judges that the random noise source is good. If the noise source is not present or is inoperable for some reason, the function should return zero. Since it isn't possible to determine if esp_random() is working correctly or not we have to simply assume that it works and return 1.

The second TRNG API defines the functions ascon_trng_init(), ascon_trng_free(), ascon_trng_generate_32(), ascon_trng_generate_64(), and ascon_trng_reseed(). These are used by masked ciphers to generate random masking material at a high data rate.

Whereas ascon_trng_generate() can take its time to generate high-quality random data, ascon_trng_generate_32() and ascon_trng_generate_64() must operate as fast as possible. In the case of the "esp" backend, the esp_random() function is as fast as we're going to get:

{
(void)state;
return esp_random();
}
{
(void)state;
return ((uint64_t)esp_random()) | (((uint64_t)esp_random()) << 32);
}
uint32_t ascon_trng_generate_32(ascon_trng_state_t *state)
Generates a 32-bit random value for masking operations.
uint64_t ascon_trng_generate_64(ascon_trng_state_t *state)
Generates a 64-bit random value for masking operations.
ascon_state_t state
[snippet_key]
Definition: snippets.c:2
State of the random number source.
Definition: ascon-trng.h:64

On some platforms, the normal random source is too slow for masking. Such backends define ASCON_TRNG_MIXER and implement a simple PRNG based on the ASCON permutation to stretch an initial seed out into an arbitrary amount of masking material. The mixer is implemented in the ascon-trng-mixer.c file.

On systems that use a mixer, the function ascon_trng_reseed() should request a new seed using the same method as ascon_trng_generate() and mix the new seed into the mixer state. This provides freshness to the random state over time when very large amounts of masking material are being generated. For the "esp", no re-seeding is required (or possible):

{
(void)state;
return 1;
}
int ascon_trng_reseed(ascon_trng_state_t *state)
Reseeds the random number source.

Escape hatch

The "none" backend provides a weak function called ascon_trng_get_bytes() that allows the application to provide its own noise source if the library was unable to find a suitable backend:

int ascon_trng_get_bytes(unsigned char *out, size_t outlen)
{
// populate the "out" buffer with "outlen" bytes of noise
...;
// return 1 to indicate that the noise is good, 0 if the
// noise source is not available or inoperable.
return 1;
}
int ascon_trng_get_bytes(unsigned char *out, size_t outlen) __attribute__((weak))
Escape hatch that allows applications to provide their own interface to the system TRNG when the libr...

The "none" backend will mix the noise data that comes from the application with system timers just in case the application noise source fails.

The escape hatch only works with the "none" backend. The weak function will be ignored if some other backend has been selected.