Overview

In the Arduino world, it’s common to generate random numbers by reading from an unconnected analog input pin. This method, which leverages the noise of the A/D converter, is a classic example of electronics ingenuity. However, owning an Arduino R4, I decided to explore the unique features it offers for generating true random numbers.

The Arduino R4 is equipped with the Renesas RA4M1 (R7FA4M1AB3CFM), which includes an encryption engine called SCE5, featuring a hardware random number generator (TRNG). Let’s see how it works.

About SCE5

SCE5 is a cryptographic accelerator developed by Renesas. It supports encryption and decryption with AES and includes a 128-bit true random number generator (TRNG).

Specifications include:

  • Access control
  • Cryptographic engine: AES
    • Key sizes: 128-bit, 256-bit
    • Encryption modes:
      • ECB, CBC, CTR (compliant with NIST SP 800-38A)
      • GCM (compliant with NIST SP 800-38D)
      • XTS (compliant with NIST SP 800-38E)
      • GCTR
    • Authenticated encryption: AES-GCM
    • Key management
  • Random number generation: 32-bit true random number generator
  • Unique ID
  • Low power consumption: Module stop mode available

*Source: https://www.renesas.com/jp/ja/document/mah/renesas-ra4m1-group-users-manual-hardware?language=en&r=1054146

I hope to try AES next time.

Researching How to Use It

The manual contains specifications and block diagrams, but it lacks detailed instructions on how to use them. From what I could gather, the SCE5 is disabled by default and needs to be enabled (that’s all it mentions).

Given this, I closed the manual and started looking around several websites that seemed like they might provide some clues:

UNO R4 TRNG and AES / Arduino Forum

Posts asking if there are sample codes to operate the R4’s TRNG. While there’s no direct runnable code, the site does offer references that seem helpful.

HW_SCE_RNG_Read() seems to be able to generate a 128bit random number, but it’s unclear which header file needs to be included.

Github arduino/ArduinoCore-renesas - Hardware-Accelerator Crypto

This issue revealed the function fsp_err_t HW_SCE_McuSpecificInit() necessary for initializing SCE5. Someone in the replies wrote about checking symbols in ’libfsp.a’, so I did the same and found some promising symbols.

00000000 T HW_SCE_McuSpecificInit
00000000 T HW_SCE_RNG_Read

Looking into arduino/ArduinoCore-renesas repository to find appropriate header files. HW_SCE_McuSpecificInit is in hw_sce_private.h, and HW_SCE_RNG_Read is in hw_sce_trng_private.h.

(By the way, this issue author wanted to compute SHA256, but SCE5 does not support hardware-assisted SHA256, so it’s not possible.)

Github renesas/fsp

The implementation of the SCE5 module’s driver and libraries can be found here, which I occasionally check out.

Source Code

Based on the information obtained from the forum and Github issues, I searched through the header files in arduino/ArduinoCore-renesas and eventually got something working.

sce_trng.ino

#ifdef __cplusplus
extern "C" {
#endif
#include <hw_sce_private.h>
#include <hw_sce_trng_private.h>
#ifdef __cplusplus
}
#endif

uint32_t rnd[4] = { 0 };
fsp_err_t err = FSP_ERR_ASSERTION;

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;

  Serial.println("PowerOn");
  HW_SCE_PowerOn();

  Serial.println("MCU Specific Init.");
  err = HW_SCE_McuSpecificInit();
  if (err != FSP_SUCCESS) {
    Serial.println("MSU Specific Init failed!");
    delay(5000);
  } else {
    Serial.println("MCU Specific Init done.");
    Serial.println("SCE5 setup complete.");
  }
}

void loop() {
  err = HW_SCE_RNG_Read(rnd);
  if (err != FSP_SUCCESS) {
    Serial.print("failed HW_SCE_RNG_Read: ");
    Serial.println(err, HEX);
  } else {
    char s[33] = {0};
    sprintf(s, "%08X%08X%08X%08X", rnd[0], rnd[1], rnd[2], rnd[3]);
    Serial.println(s);
  }
  delay(1000);
}

Operation Check

Arduino R4 MINIMA SCE5 TRNG Sample

It seems to be working. It sends a 128bit random number to the PC via serial communication every second.

Troubleshooting Compile Issues

There are places in r_sce_if.h where C++ reserved words are used, causing compile errors. The source code I provided doesn’t directly include it, but it’s included due to dependencies. I’ve just rewritten r_sce_if.h for now.

/* RSA 1024bit key index pair structure */
typedef struct sce_rsa1024_key_pair_index
{
    sce_rsa1024_private_key_index_t    private; // Changed 'private' to 'priv_key'
    sce_rsa1024_public_key_index_t     public;  // Changed 'public' to 'pub_key'
} sce_rsa1024_key_pair_index_t;

This file also contains several other places where public, private are used, so replace them all.

rce_if.h is located in the following path (On MacOS).

for MINIMA:

/Users/{username}/Library/Arduino15/packages/arduino/hardware/renesas_uno/1.1.0/variants/MINIMA/includes/ra/fsp/src/r_sce/crypto_procedures/src/sce5/plainkey/public/inc/r_sce_if.h

for WiFi version:

/Users/{username}/Library/Arduino15/packages/arduino/hardware/renesas_uno/1.1.0/variants/UNOWIFIR4/includes/ra/fsp/src/r_sce/crypto_procedures/src/sce5/plainkey/public/inc/r_sce_if.h

How to Operate SCE5’s TRNG

I don’t fully understand it, but I’ll explain as much as I can.

Enabling the Module (Disabling Low Power Mode)

SCE5 appears to be disabled by default, so first, the module needs to be enabled.

Include hw_sce_common.h and execute the following function.

HW_SCE_PowerOn();

HW_SCE_PowerOn() is equivalent to the following operation:

R_MSTP->MSTPCRC_b.MSTPC31 = 0;

According to the manual, b31 of the Module Stop Control Register C (MSTPCRC) acts as the enable/disable flag for SCE5. By default, it is set to 1 (disabled), so set it to 0 to enable.

Initializing the SCE5 Module

HW_SCE_McuSpecificInit() is required for module initialization.

Internally, it seems to perform the following processes, but the details are unclear. Something like initializing and performing self-diagnostics?

HW_SCE_SoftwareResetSub();
HW_SCE_SelfCheck1Sub();
HW_SCE_SelfCheck2Sub();

Implementations are available at https://github.com/renesas/fsp, but it’s unclear what each function does.

This initialization function returns an fsp_err_t type, indicating success or failure. Successful returns FSP_SUCCESS, and failures might return errors like FSP_ERR_CRYPTO_SCE_FAIL, FSP_ERR_CRYPTO_SCE_RESOURCE_CONFLICT, or FSP_ERR_CRYPTO_SCE_RETRY.

fsp_err_t is defined in fsp_common_api.h.

Regarding errors, you might ignore FSP_ERR_CRYPTO_SCE_FAIL, but retrying might work for the other errors (not very sure).

Calling the Random Number Generation Function

HW_SCE_RNG_Read() generates a 128-bit random number. If FSP_SUCCESS is returned, it succeeded; otherwise, it failed. Probably retrying would be okay?

Usage Precautions

The manual mentions a 32-bit true random number generator; however, the HW_SCE_RNG_Read() function generates a 128-bit random number in one go and writes it to the passed address. Therefore, to use this function safely, you need to allocate memory for 128 bits (32 bits x 4). If the specified area is insufficient, a buffer overflow may occur, leading to program malfunctions and security risks, so caution is necessary.

Example of incorrect usage:

uint32_t rnd32;
HW_SCE_RNG_Read(&rnd32);  // Writing 128 bits of data will cause a buffer overflow.

Example of correct usage:

uint32_t rnd[4] = {0};  // Allocating space for 128 bits.
HW_SCE_RNG_Read(rnd);

Speed and Quality Evaluation

I have not conducted any evaluations of speed or quality this time, but I plan to consider them in the future. As for the quality, since I am not an expert in cryptography, a deep analysis is challenging. However, I intend to try running random number tests such as NIST SP 800-22 and DIEHARD.