Asymmetric Crypto Engine

Introduction

The Asymmetric Crypto Engine (PKE) is a dedicated hardware acceleration unit within the SoC for handling public-key cryptographic operations. Compared with software implementations, the hardware acceleration engine can significantly improve the execution efficiency of asymmetric cryptographic algorithms while protecting key security through a physical isolation mechanism, playing an important role in IoT security systems.

Application Background

In IoT device security scenarios, asymmetric cryptographic algorithms are widely used in critical security processes such as digital signatures, key exchange, and identity authentication. However, such algorithms involve a large number of complex mathematical operations (e.g., large-number modular exponentiation and elliptic curve point multiplication). If implemented entirely in software, they consume significant CPU resources with low execution efficiency. The Asymmetric Crypto Engine implements these core operations through dedicated hardware circuits, greatly improving operation speed while ensuring security.

Working Principle

The Asymmetric Crypto Engine connects to the CPU through the APB bus and internally contains dedicated computation units and storage units. When the application layer needs to perform an asymmetric cryptographic operation, the CPU writes the operation parameters into the engine’s registers and memory area, configures the control register to start the operation, and the engine hardware automatically completes the core cryptographic operation and returns the result. The entire process is transparent to the upper-layer application, and the user can complete the operation through APIs.

Security Features

The Asymmetric Crypto Engine fully considers security protection requirements in its architecture design:

  • Physical isolation: The engine’s internal storage unit is isolated from the system bus, preventing keys from being stolen by bus sniffing attacks.

  • OTP key support: Supports pre-burning private keys into the OTP (One Time Programmable) region. The OTP key is directly connected to the engine and cannot be read or tampered with externally.

  • Side-channel attack protection: Some chip models support DPA (Differential Power Analysis), SPA (Simple Power Analysis), and Timing Attack protection.

  • TrustZone support: Some chip models support ARM TrustZone technology and can automatically identify the CPU’s secure/non-secure access state.

Advantages

Compared with a pure software implementation, the Asymmetric Crypto Engine offers the following advantages:

  • High performance: Hardware acceleration significantly shortens operation time and reduces CPU usage.

  • Low power consumption: Dedicated hardware circuits consume less power than running software algorithms on a general-purpose CPU.

  • High security: The physical isolation mechanism and OTP key storage effectively prevent key leakage.

  • Ease of use: Provides well-encapsulated API interfaces, so users do not need to be concerned with low-level hardware details.

Functional Architecture

The following lists the functional specifications of the Asymmetric Crypto Engine by chip series, including the basic functions.

RTL8721Dx:

Not supported.

OTP Keys

In addition to software keys, the engine also supports pre-burning private keys into the OTP region. The OTP key is directly connected to the engine through a physical isolation mechanism and cannot be read or tampered with externally. It is the recommended solution for protecting core private keys in production environments.

RTL8721Dx:

Not supported.

Working Principle

The Asymmetric Crypto Engine connects to the CPU through the APB bus and operates in Slave mode. The engine internally contains computation units, storage units, and control registers. The CPU completes operation parameter configuration and result retrieval by reading and writing these registers.

To ensure concurrency safety in a multitasking environment, the engine has a built-in hardware mutex mechanism. When a Secure-state CPU holds the lock, all Non-secure accesses are blocked; if a Non-secure CPU holds the lock, the Secure CPU can forcibly acquire usage rights through a dedicated preemption register, ensuring priority for secure tasks.

Workflow

The standard operation flow of the engine is as follows:

  1. Acquire the mutex: The CPU acquires the engine’s hardware mutex.

  2. Write operation parameters: Write the algorithm parameters into the engine’s storage unit.

  3. Configure operation mode: Set the control register to select the required operation mode.

  4. Start the operation: Enable the engine to start the computation.

  5. Monitor operation progress: Poll the status register to monitor operation progress.

  6. Retrieve operation result: After detecting the completion flag bit, read the operation result from the storage unit.

  7. Release the mutex: Release the mutex so that other tasks can use the engine.

Exception Handling

The engine provides the following exception handling mechanisms:

  • Error identification: The status register contains error flag bits; if an error is detected during polling, the process can be terminated immediately.

  • Error feedback: The API returns predefined error codes (a non-zero value indicates an error, and 0 indicates normal completion).

Usage

After introducing the engine’s working principle and flow, the following describes how to use the engine. The engine provides two usage methods: the low-level direct API and the MbedTLS integrated API.

Development Phase

During the development phase, users typically use software keys for functional verification and debugging:

  1. Select the API type:

    • Use the low-level API to directly control the engine, which offers more comprehensive functionality but requires an understanding of the engine’s working principle.

    • Use the MbedTLS integrated API, which is more general but only supports software keys.

  2. Configure the SDK:

    • Enable the Asymmetric Crypto Engine related options in SDK menuconfig.

    • Select the supported algorithm curves according to requirements.

  3. Call the API:

    • Refer to the example code to call the corresponding API to complete key generation, signing, or verification operations.

Production Phase

During the production phase, OTP keys are recommended for higher security:

  1. Generate the key pair:

    • Generate the public/private key pair during the development phase.

    • Save the public key for signature verification and the private key for OTP burning.

  2. Burn the OTP key:

    • Burn the private key to the specified OTP address (see the OTP key table above).

    • Configure the key read protection/write protection bits.

    Warning

    The OTP (One Time Programmable) region can be written only once and cannot be erased or revoked. Carefully verify the address and data before executing the write command.

  3. Use the low-level API:

    • The low-level API must be used when using OTP keys.

    • The MbedTLS API does not support OTP keys.

API

Whether using software keys or OTP keys, Realtek provides comprehensive API interfaces, so users do not need to be concerned with low-level register operation details.

Raw API

The Raw API provides full control over the engine and supports both software keys and OTP keys:

  • Key generation API: Generates ECC or RSA key pairs.

  • Signing API: Uses the private key to digitally sign data.

  • Verification API: Uses the public key to verify signature validity.

  • Key exchange API: Performs ECDH key exchange.

  • OTP key configuration API: Configures the access permissions of OTP keys.

MbedTLS API

To improve compatibility, Realtek has integrated the hardware acceleration engine into the MbedTLS API. Users can use the standard MbedTLS ECDSA/ECDH API, with hardware acceleration automatically invoked underneath. The MbedTLS API only supports software keys, not OTP keys. Due to hardware limitations, MbedTLS support for the SECP521R1 curve has been disabled.

Supported Algorithms and Curves

The algorithm curves supported by each chip are listed below. Common curve parameters are pre-built into the ROM, so users do not need to provide them additionally:

RTL8721Dx:

Not supported.

Raw API

PKE Exported Types

enum pke_ecp_curve_id

ECC curve identifier.

Values:

/* Curve not defined. */
PKE_ECP_CURVE_NONE = 0

/* Domain parameters for the 192-bit curve defined by FIPS 186-4 and SEC1. */
PKE_ECP_CURVE_SECP192R1

/* Domain parameters for the 224-bit curve defined by FIPS 186-4 and SEC1. */
PKE_ECP_CURVE_SECP224R1

/* Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */
PKE_ECP_CURVE_SECP256R1

/* Domain parameters for the 384-bit curve defined by FIPS 186-4 and SEC1. */
PKE_ECP_CURVE_SECP384R1

/* 521-bit curve not supported. */
PKE_ECP_CURVE_NULL

/* Domain parameters for 256-bit Brainpool curve. */
PKE_ECP_CURVE_BP256R1

/* Domain parameters for 384-bit Brainpool curve. */
PKE_ECP_CURVE_BP384R1

/* Domain parameters for 512-bit Brainpool curve. */
PKE_ECP_CURVE_BP512R1

/* Domain parameters for Curve25519. */
PKE_ECP_CURVE_CURVE25519

/* Domain parameters for 192-bit "Koblitz" curve. */
PKE_ECP_CURVE_SECP192K1

/* Domain parameters for 224-bit "Koblitz" curve. */
PKE_ECP_CURVE_SECP224K1

/* Domain parameters for 256-bit "Koblitz" curve. */
PKE_ECP_CURVE_SECP256K1

/* Domain parameters for Curve448. */
PKE_ECP_CURVE_CURVE448

/* Supported by default ROM driver. */
PKE_ECP_CURVE_ED25519

/* Not supported by default; the user can add support manually. */
PKE_ECP_CURVE_ED448
typedef struct pke_ecp_group pke_ecp_group

PKE ECP Group.

Public Members

pke_ecp_curve_id curve_id

value in pke_ecp_curve_id.

uint32_t precise_bits

ECC operand precision in bits.

uint8_t curve_field

PKE_MODE_MAIN_ECC_PRIME, PKE_MODE_MAIN_ECC_BINARY or PKE_MODE_MAIN_EDWARDS.

uint8_t curve_is_Montgomery

1 for Montgomery curve (PKE_MASK_CONTROL_MODE_MAIN must be 2’b11), 0 otherwise.

uint8_t A_size

Size of parameter A in byte.

uint8_t B_size

Size of parameter B in byte.

uint8_t P_size

Size of parameter P in byte.

uint8_t N_size

Size of parameter N in byte.

uint8_t Gx_size

Size of parameter Gx in byte.

uint8_t Gy_size

Size of parameter Gy in byte.

uint8_t Gz_size

Size of parameter Gz in bytes.

uint8_t *A_p

Pointer to parameter A.

uint8_t *B_p

Pointer to parameter B.

uint8_t *P_p

Pointer to parameter P.

uint8_t *N_p

Pointer to parameter N.

uint8_t *Gx_p

Pointer to parameter Gx.

uint8_t *Gy_p

Pointer to parameter Gy.

uint8_t *Gz_p

Pointer to parameter Gz.

typedef struct pke_ecp_point pke_ecp_point

PKE ECP Point.

Public Members

uint8_t is_inited

Set to 1 when the point is initialized, 0 otherwise.

uint8_t *X_p

The X coordinate of the ECP point.

uint8_t X_size

The X coordinate size in byte.

uint8_t *Y_p

The Y coordinate of the ECP point.

uint8_t Y_size

The Y coordinate size in bytes.

uint8_t *Z_p

The Z coordinate of the ECP point.

uint8_t Z_size

The Z coordinate size in bytes.

PKE Exported Constants

PKE ECC

/* Max: ECC 512 bits. */
#define PKE_ECC_PARAMETER_SIZE (0x40)

/* ECC Curve parameter Modulus. */
#define PKE_ECC_PARAMETER_ADDR_P ((void *)(PKE_MMEM_BASE + 0x0))

/* ECC Exponent. */
#define PKE_ECC_PARAMETER_ADDR_E ((void *)(PKE_MMEM_BASE + 0x40))

/* ECC Curve parameter a. */
#define PKE_ECC_PARAMETER_ADDR_A ((void *)(PKE_MMEM_BASE + 0x80))

/* ECC Curve parameter b / d. */
#define PKE_ECC_PARAMETER_ADDR_B ((void *)(PKE_MMEM_BASE + 0x100))

/* ECC Curve base point x. */
#define PKE_ECC_PARAMETER_ADDR_G_x ((void *)(PKE_MMEM_BASE + 0x140))

/* ECC Curve base point y. */
#define PKE_ECC_PARAMETER_ADDR_G_y ((void *)(PKE_MMEM_BASE + 0x180))

/* ECC Curve base point z, set to 1. */
#define PKE_ECC_PARAMETER_ADDR_G_z ((void *)(PKE_MMEM_BASE + 0x1C0))

/* ECC Result x. */
#define PKE_ECC_PARAMETER_ADDR_RES_x ((void *)(PKE_TMEM_BASE))

/* ECC Result y. */
#define PKE_ECC_PARAMETER_ADDR_RES_y ((void *)(PKE_TMEM_BASE + 0x40))

/* ECC Curve parameter order. */
#define PKE_ECC_PARAMETER_ADDR_N ((void *)(PKE_MMEM_BASE + 0x400))

PKE ECDSA Private Key Selection

/* Use OTP hardware key port 0 ({hw_key2, hw_key1}, 512-bit). */
#define PKE_ECDSA_PRIV_KEY_HW_0 (0)

/* Use OTP hardware key port 1 ({0, hw_key2}, 512-bit). */
#define PKE_ECDSA_PRIV_KEY_HW_1 (1)

/* Use software-provided ECDSA private key. */
#define PKE_ECDSA_PRIV_KEY_SW (2)

/* Check whether the given ID is a valid ECDSA private key selection. */
#define IS_PKE_ECDSA_PRIV_KEY (((ID) == PKE_ECDSA_PRIV_KEY_HW_0) || \
    ((ID) == PKE_ECDSA_PRIV_KEY_HW_1) || \
    ((ID) == PKE_ECDSA_PRIV_KEY_SW))

/* Check whether the given ID selects a secure OTP hardware key. */
#define IS_PKE_ECDSA_SECURE_HW_KEY (((ID) == PKE_ECDSA_PRIV_KEY_HW_0) || \
    ((ID) == PKE_ECDSA_PRIV_KEY_HW_1))
RTL8721F:

Not supported.

PKE Engine Memory

/* Base address of PKE main memory (MMEM). */
#define PKE_MMEM_BASE ((int)pke_get_pke_addr() + 0x10000)

/* Base address of PKE temporary memory (TMEM). */
#define PKE_TMEM_BASE ((int)pke_get_pke_addr() + 0x20000)

PKE Error Code

/* Prime check error for modular number. */
#define PKE_STATUS_PRIME_CHK_ERR (0x1)

/* R^2 mod N calculation failed. */
#define PKE_STATUS_R2MOD_N_FAILED (0x2)

/* ECC odd point error (Y coordinate is 0). */
#define PKE_STATUS_ECC_ODD_POINT (0x4)

/* Invalid or unsupported PKE function. */
#define PKE_STATUS_INVALID_FUNCTION (0x7)

/* ECC Z coordinate equals zero. */
#define PKE_STATUS_ECC_Z (0x8)

/* EdDSA point decompression failed. */
#define PKE_STATUS_EDDSA_FAIL (0x9)

/* Modular inverse computation failed. */
#define PKE_STATUS_MOD_INV_FAILED (0x10)

/* RSA input message is larger than modulus N. */
#define PKE_STATUS_RSA_INVALID_MESSAGE (0x20)

/* No valid exponent found. */
#define PKE_STATUS_NO_VALID_EXP (0x40)

PKE Mode

/* ECC prime field operation mode. */
#define PKE_MODE_MAIN_ECC_PRIME (0x0)

/* ECC binary field operation mode. */
#define PKE_MODE_MAIN_ECC_BINARY (0x1)

/* RSA operation mode. */
#define PKE_MODE_MAIN_RSA (0x2)

/* Edwards or Montgomery curve operation mode. */
#define PKE_MODE_MAIN_EDWARDS_MONTGOMERY (0x3)

PKE Other Function ID

/* Clear PKE engine state and abort any ongoing operation. */
#define PKE_FUNCTION_ENTRY_CLEAR (0x0)

/* Modular multiplication: A * B mod N. */
#define PKE_FUNCTION_ENTRY_PUBKEY_MOD_MUL (0x2)

/* Modular addition: A + B mod N. */
#define PKE_FUNCTION_ENTRY_PUBKEY_MOD_ADD (0x3)

/* ECC scalar multiplication with private key: k * P. */
#define PKE_FUNCTION_ENTRY_ECDSA_MUL_PRIVATE (0x4)

/* Compute Montgomery constant R^2 mod N for Montgomery reduction. */
#define PKE_FUNCTION_ENTRY_PUBKEY_R_SQAR (0x5)

/* Compute Montgomery constant -N^{-1} mod R. */
#define PKE_FUNCTION_ENTRY_PUBKEY_N_INV (0x6)

/* Modular inverse: k^{-1} mod N. */
#define PKE_FUNCTION_ENTRY_PUBKEY_K_INV (0x7)

/* ECC point addition: P + Q on the configured curve. */
#define PKE_FUNCTION_ENTRY_PUBKEY_ECC_ADD_POINT (0x8)

/* Copy point P into operand A register for subsequent operations. */
#define PKE_FUNCTION_ENTRY_PUBKEY_SET_A_FROM_P (0xA)

/* Binary field (GF(2^m)) polynomial multiplication. */
#define PKE_FUNCTION_ENTRY_PUBKEY_MOD_MUL_BIN (0xB)

/* Binary field (GF(2^m)) XOR (addition): A XOR B. */
#define PKE_FUNCTION_ENTRY_PUBKEY_MOD_XOR (0xC)

/* Reduction: X mod N. */
#define PKE_FUNCTION_ENTRY_PUBKEY_X_MOD_N (0xE)

/* Modular subtraction: A - B mod N. */
#define PKE_FUNCTION_ENTRY_PUBKEY_MOD_SUB (0xF)

/* Miller-Rabin primality witness test. */
#define PKE_FUNCTION_ENTRY_WITNESS (0x10)

/* Big-number multiplication (no modular reduction). */
#define PKE_FUNCTION_ENTRY_BIG_NUM_MUL (0x12)

/* Compute P * Q for RSA prime pair. */
#define PKE_FUNCTION_ENTRY_PQ_MOD (0x13)

/* Simplified ECDSA key generation (hardware-accelerated). */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_ECDSA_GEN (0x18)

/* Simplified ECDSA signature generation (hardware-accelerated). */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_ECDSA_SIGN (0x19)

/* Simplified ECDSA signature verification (hardware-accelerated). */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_ECDSA_VERIFY (0x1A)

/* Simplified EdDSA key generation (hardware-accelerated). */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_EDDSA_GEN (0x1B)

/* Simplified EdDSA signing step 1: compute nonce point R. */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_EDDSA_SIGN_R (0x1C)

/* Simplified EdDSA signing step 2: compute scalar S. */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_EDDSA_SIGN_S (0x1D)

/* Simplified EdDSA signature verification (hardware-accelerated). */
#define PKE_FUNCTION_ENTRY_SIMPLIFY_EDDSA_VERIFY (0x1E)

/* Check whether a curve ID identifies a Montgomery or Edwards curve (Curve25519, Curve448, Ed25519, Ed448). */
#define PKE_ECC_IS_MONTGOMERY_EDWARDS_CURVE (((CURVE_ID) == PKE_ECP_CURVE_CURVE25519) || \
    ((CURVE_ID) == PKE_ECP_CURVE_CURVE448) || \
    ((CURVE_ID) == PKE_ECP_CURVE_ED25519) || \
    ((CURVE_ID) == PKE_ECP_CURVE_ED448))

PKE RSA

/* Max: RSA-4096. */
#define PKE_RSA_PARAMETER_SIZE (0x200)

/* RSA Modulus. */
#define PKE_RSA_PARAMETER_ADDR_N ((void *)(PKE_MMEM_BASE + 0x0))

/* RSA Exponent. */
#define PKE_RSA_PARAMETER_ADDR_E ((void *)(PKE_MMEM_BASE + 0x200))

/* RSA Message. */
#define PKE_RSA_PARAMETER_ADDR_A ((void *)(PKE_MMEM_BASE + 0x400))

/* RSA Result. */
#define PKE_RSA_PARAMETER_ADDR_RES ((void *)(PKE_TMEM_BASE))

/* Miller-Rabin witness test: modulus N memory address. */
#define PKE_RSA_WITNESS_N ((void *)(PKE_MMEM_BASE + 0x0))

/* Miller-Rabin witness test: base A memory address. */
#define PKE_RSA_WITNESS_A ((void *)(PKE_MMEM_BASE + 0x400))

/* Miller-Rabin witness test: result memory address. */
#define PKE_RSA_WITNESS_RES ((void *)(PKE_TMEM_BASE))

/* RSA prime multiplication: prime factor P memory address. */
#define PKE_RSA_PRIME_MUL_P ((void *)(PKE_MMEM_BASE + 0x0))

/* RSA prime multiplication: prime factor Q memory address. */
#define PKE_RSA_PRIME_MUL_Q ((void *)(PKE_MMEM_BASE + 0x180))

/* RSA prime multiplication: result (P*Q) memory address. */
#define PKE_RSA_PRIME_MUL_RES ((void *)(PKE_TMEM_BASE))

PKE Simplified ECDSA

/* Simplified ECDSA message hash length in bits. */
#define PKE_ECC_TMEM_ADDR_ECDSA_HASH_LEN ((void *)(PKE_TMEM_BASE + 0x7C4))

/* Simplified ECDSA per-signature random nonce (scalar k) for signing. */
#define PKE_ECC_TMEM_ADDR_ECDSA_RAND ((void *)(PKE_TMEM_BASE + 0x2C0))

/* Simplified ECDSA signing result R. */
#define PKE_ECC_TMEM_ADDR_ECDSA_SIGN_R ((void *)(PKE_TMEM_BASE + 0x340))

/* Simplified ECDSA signing result S. */
#define PKE_ECC_TMEM_ADDR_ECDSA_SIGN_S ((void *)(PKE_TMEM_BASE + 0x3C0))

/* Simplified ECDSA public key x. */
#define PKE_ECC_TMEM_ADDR_ECDSA_PUBKEY_x ((void *)(PKE_TMEM_BASE + 0x240))

/* Simplified ECDSA public key y. */
#define PKE_ECC_TMEM_ADDR_ECDSA_PUBKEY_y ((void *)(PKE_TMEM_BASE + 0x280))

/* Simplified ECDSA recovered point rQ used for signature verification. */
#define PKE_ECC_TMEM_ADDR_ECDSA_VERIFY_RQ ((void *)(PKE_TMEM_BASE + 0x540))

PKE Simplified ECDSA EdDSA

/* Function entries. */
#define PKE_ECC_TMEM_FUNCTION_ENTRY ((void *)(PKE_TMEM_BASE + 0x0))

/* Simplified ECDSA/EdDSA curve modulus. */
#define PKE_ECC_TMEM_ADDR_P ((void *)(PKE_TMEM_BASE + 0x80))

/* Simplified ECDSA/EdDSA private key. */
#define PKE_ECC_TMEM_ADDR_E ((void *)(PKE_TMEM_BASE + 0xC0))

/* Simplified ECDSA/EdDSA curve parameter a. */
#define PKE_ECC_TMEM_ADDR_A ((void *)(PKE_TMEM_BASE + 0x100))

/* Simplified ECDSA curve parameter b / d. */
#define PKE_ECC_TMEM_ADDR_B ((void *)(PKE_TMEM_BASE + 0x140))

/* Simplified ECDSA/EdDSA curve base point x. */
#define PKE_ECC_TMEM_ADDR_G_x ((void *)(PKE_TMEM_BASE + 0x180))

/* Simplified ECDSA/EdDSA curve base point y. */
#define PKE_ECC_TMEM_ADDR_G_y ((void *)(PKE_TMEM_BASE + 0x1C0))

/* Simplified ECDSA/EdDSA curve point z, set to 1. */
#define PKE_ECC_TMEM_ADDR_G_z ((void *)(PKE_TMEM_BASE + 0x200))

/* Simplified ECDSA/EdDSA curve order. */
#define PKE_ECC_TMEM_ADDR_N ((void *)(PKE_TMEM_BASE + 0x300))

/* Simplified ECDSA: message hash; Simplified EdDSA: hashed private key. */
#define PKE_ECC_TMEM_ADDR_HASH ((void *)(PKE_TMEM_BASE + 0x380))

PKE Simplified EdDSA

/* Simplified EdDSA encoded public key. */
#define PKE_ECC_TMEM_ADDR_EdDSA_PUBKEY ((void *)(PKE_TMEM_BASE + 0x540))

/* Simplified EdDSA message to be signed. */
#define PKE_ECC_TMEM_ADDR_EdDSA_SIGN_MSG ((void *)(PKE_TMEM_BASE + 0x580))

/* Simplified EdDSA signing result R. */
#define PKE_ECC_TMEM_ADDR_EdDSA_SIGN_R ((void *)(PKE_TMEM_BASE + 0x640))

/* Simplified EdDSA signing result S. */
#define PKE_ECC_TMEM_ADDR_EdDSA_SIGN_S ((void *)(PKE_TMEM_BASE + 0x6C0))

/* Simplified EdDSA message to be verified. */
#define PKE_ECC_TMEM_ADDR_EdDSA_VERIFY_MSG ((void *)(PKE_TMEM_BASE + 0x340))

/* Simplified EdDSA verify B_x value. */
#define PKE_ECC_TMEM_ADDR_EdDSA_VERIFY_B_x ((void *)(PKE_TMEM_BASE + 0x440))

/* Simplified EdDSA verify B_y value. */
#define PKE_ECC_TMEM_ADDR_EdDSA_VERIFY_B_y ((void *)(PKE_TMEM_BASE + 0x480))

/* Simplified EdDSA verification result A_x; if A == B, verification succeeds. */
#define PKE_ECC_TMEM_ADDR_EdDSA_VERIFY_A_x ((void *)(PKE_TMEM_BASE + 0x740))

/* Simplified EdDSA verification result A_y; if A == B, verification succeeds. */
#define PKE_ECC_TMEM_ADDR_EdDSA_VERIFY_A_y ((void *)(PKE_TMEM_BASE + 0x780))

PKE Timeout

/* Mutex acquisition timeout in polling loop iterations. */
#define PKE_MUTEX_TIMEOUT ((u32) 1000000)

/* PKE engine operation timeout in polling loop iterations. */
#define PKE_TIMEOUT_CNT (0x100000)

PKE Exported Functions

int pke_ecdsa_genkey(pke_ecp_group *grp, int8_t key_id, uint8_t *pri_key_p, uint8_t pri_key_size, uint8_t *pub_key_x, uint8_t *pub_key_y)

Derive the ECDSA public key from the given private key.

Parameters:
  • grp – Pointer to the pke_ecp_group structure.

  • key_id – One of PKE ECDSA Private Key Selection group

  • pri_key_p – Pointer to the software private key in little-endian format, or NULL when using a hardware OTP key.

  • pri_key_size – SW key size in byte

  • pub_key_x – Pointer to the output buffer for the x-coordinate of the public key (little-endian format).

  • pub_key_y – Pointer to the output buffer for the y-coordinate of the public key (little-endian format).

Returns:

0 on success, or an error code on failure.

void pke_ecdsa_lalu_hash_process(uint8_t *buf_out, uint8_t *hash_in, uint32_t hash_len_byte, uint32_t precise_bit)

Pre-process a hash value for use with the ECDSA PKE engine.

Parameters:
  • buf_out – Output buffer for the hash value formatted for the PKE engine.

  • hash_in – Hash result from a software library or the hardware HMAC engine.

  • hash_len_byte – HASH length in bytes

  • precise_bit – Bit-length (precision) of the ECC curve.

int pke_ecdsa_read_signature(pke_ecp_group *grp, uint8_t *pub_key_x_p, uint8_t *pub_key_y_p, uint8_t *HASH_p, uint8_t HASH_size_byte, uint8_t *sign_r, uint8_t *sign_s)

Verify an ECDSA signature (r, s) for the given hash using the specified public key and elliptic curve group.

Parameters:
  • grp – Pointer to the pke_ecp_group structure.

  • pub_key_x_p – Pointer to the x-coordinate of the public key.

  • pub_key_y_p – Pointer to the y-coordinate of the public key.

  • HASH_p – Pointer to the hash of the message whose signature is to be verified.

  • HASH_size_byte – Size of the hash in bytes.

  • sign_r – Pointer to the ‘r’ component of the provided signature.

  • sign_s – Pointer to the ‘s’ component of the provided signature.

Returns:

Returns RTK_SUCCESS if the signature is valid, or an error code on failure.

int pke_ecdsa_share_hw_key(int8_t key_id, int8_t is_share)

Configure the sharing attribute of an OTP hardware key (secure-only or shared with non-secure world).

Parameters:
  • key_id – PKE_ECDSA_PRIV_KEY_HW_0 or PKE_ECDSA_PRIV_KEY_HW_1.

  • is_share – 1 to share the key with the non-secure world, 0 for secure-only access.

Return values:
  • RTK_SUCCESS – Key sharing configuration updated successfully.

  • _ERRNO_CRYPTO_KEY_SECURE_ERR – Called from non-secure context.

int pke_ecdsa_write_signature(pke_ecp_group *grp, int8_t key_id, uint8_t *rand_p, uint8_t rand_size, uint8_t *pri_key_p, uint8_t pri_key_size, uint8_t *HASH_p, uint8_t HASH_size_byte, uint8_t *sign_r, uint8_t *sign_s)

Generate an ECDSA signature (r, s) for the provided hash using a specified elliptic curve group.

Parameters:
  • grp – Pointer to the pke_ecp_group structure.

  • key_id – One of PKE ECDSA Private Key Selection specifying which private key to use for signing.

  • rand_p – Pointer to the per-signature random nonce (k), must be cryptographically random and never reused.

  • rand_size – Size of the random value in bytes.

  • pri_key_p – Pointer to the software private key used for signing, or NULL when using a hardware OTP key.

  • pri_key_size – Size of the private key in bytes.

  • HASH_p – Pointer to the hash of the message to be signed.

  • HASH_size_byte – Size of the hash in bytes.

  • sign_r – Pointer to the buffer where the ‘r’ component of the signature will be stored.

  • sign_s – Pointer to the buffer where the ‘s’ component of the signature will be stored.

Returns:

Returns 0 on success, or an error code on failure.

int pke_ecp_group_init_in_rom(pke_ecp_group *grp, pke_ecp_curve_id curve_id)

Initialize ECC curve parameters.

Parameters:
Return values:
  • RTK_SUCCESS – ECC curve parameters initialized successfully.

  • RTK_FAIL – The specified curve ID is not supported by the ROM code.

int pke_eddsa_ed25519_genkey(uint8_t *priv_key_le, uint8_t *pub_key_le)

Derive the Ed25519 public key from an existing private key (seed).

Parameters:
  • priv_key_le – Pointer to the input private key (32-byte seed) in little-endian format.

  • pub_key_le – Pointer to a buffer where the generated public key will be stored. The public key will be in little-endian format.

Returns:

Returns 0 on successful key pair generation, or an error code on failure.

Note

This function derives the Ed25519 public key from the given private key (seed). The public key is output in little-endian format, which may need to be converted for use with external libraries.

int pke_eddsa_ed25519_read_signature(uint8_t *message, size_t msg_len, uint8_t *pub_key_le, uint8_t *sign_r, uint8_t *sign_s)

Verify an Ed25519 digital signature for the given message using the provided public key.

Parameters:
  • message – Pointer to the message buffer that was signed.

  • msg_len – Length of the message in bytes.

  • pub_key_le – Pointer to the buffer containing the public key in little-endian format. This key is used to verify the authenticity of the signature.

  • sign_r – Pointer to the buffer containing the R component of the signature.

  • sign_s – Pointer to the buffer containing the S component of the signature.

Returns:

Returns 0 if the signature is valid and matches the provided message and public key, or an error code if the verification fails.

Note

This function performs the Ed25519 signature verification process. It checks that the signature (R, S) corresponds to the message under the given public key. Ensure that all input buffers are correctly sized for Ed25519: exactly 32 bytes for the public key, sign_r, and sign_s each.

int pke_eddsa_ed25519_write_signature(uint8_t *message, size_t msg_len, uint8_t *priv_key_le, uint8_t *sign_r, uint8_t *sign_s)

Generate an Ed25519 digital signature for the given message using the provided private key and R value.

Parameters:
  • message – Pointer to the message buffer that needs to be signed.

  • msg_len – Length of the message in bytes.

  • priv_key_le – Pointer to the buffer containing the private key in little-endian format. This key is used in the signature generation.

  • sign_r – Pointer to the output buffer where the computed R component of the signature will be stored.

  • sign_s – Pointer to the buffer where the generated S value of the signature will be stored. The buffer should be appropriately sized for the signature component.

Returns:

Returns 0 on successful signature generation, or an error code on failure.

Note

This function performs the complete Ed25519 signature generation, computing both the R and S components of the signature (R, S). This function computes both the R and S components internally. Both sign_r and sign_s are output buffers and must each be at least 32 bytes. Ensure that the provided buffers are correctly initialized and of sufficient size to prevent any memory issues.

int pke_eddsa_genkey(pke_ecp_group *grp, uint8_t *hashed_key_p, uint8_t *pub_key_encode_p)

Generate an encoded public key for use in EdDSA (Edwards-curve Digital Signature Algorithm) given a hashed private key.

Parameters:
  • grp – Pointer to the pke_ecp_group structure.

  • hashed_key_p – Pointer to the buffer containing the hashed private key.

  • pub_key_encode_p – Pointer to the buffer where the encoded public key will be stored.

Returns:

Returns 0 on success, or an error code on failure.

int pke_eddsa_read_signature(pke_ecp_group *grp, uint8_t *pub_key_p, uint8_t *k_buf, uint8_t k_size, uint8_t *sign_r, uint8_t *sign_s)

Verify an EdDSA signature (R, S) using the provided public key and additional buffers.

Parameters:
  • grp – Pointer to the pke_ecp_group structure.

  • pub_key_p – Pointer to the buffer containing the public key used for signature verification.

  • k_buf – Pointer to the buffer containing the pre-computed scalar k = SHA512(R || A || M) used in EdDSA verification.

  • k_size – Size of the k_buf buffer in bytes.

  • sign_r – Pointer to the buffer containing the R component of the signature.

  • sign_s – Pointer to the buffer containing the S component of the signature.

Returns:

Returns 0 on successful verification, or an error code on failure.

void pke_engine_init(void)

Initialize PKE engine.

  1. Enable clock and release reset

  2. Initialize engine memory (MMEM / TMEM) to zero.

  3. Set PKE HW key to secure only

RTL8721F:

Not supported.