SM3 Hash Accelerator
SM3 (GM/T 0004-2012) is a cryptographic hash function of the Chinese ShangMi (SM) standards. It reads the message in 64-byte blocks and produces a 256-bit digest, comparable to SHA-256. On ESP32-C5, the SHA accelerator computes SM3 in hardware.
The esp_sm3 API is the only interface to the SM3 hardware. SM3 is not available through the Mbed TLS or PSA Crypto APIs.
One-Shot Digest
Use esp_sm3() when the whole message is in one buffer:
#include "esp_sm3.h"
uint8_t digest[ESP_SM3_DIGEST_LEN];
esp_err_t err = esp_sm3(message, message_len, digest, sizeof(digest));
if (err != ESP_OK) {
// No digest was written. Handle the error.
}
Streaming Digest
Use the context functions when the message arrives in parts:
#include "esp_sm3.h"
uint8_t digest[ESP_SM3_DIGEST_LEN];
esp_sm3_ctx_handle_t ctx = NULL;
esp_err_t err = esp_sm3_create(&ctx);
if (err != ESP_OK) {
return err;
}
err = esp_sm3_update(ctx, part1, part1_len);
if (err == ESP_OK) {
err = esp_sm3_update(ctx, part2, part2_len);
}
if (err == ESP_OK) {
err = esp_sm3_finish(ctx, digest, sizeof(digest));
}
esp_sm3_delete(ctx);
esp_sm3_create() allocates the context and writes the handle to ctx. If the function returns ESP_ERR_NO_MEM or ESP_ERR_NOT_SUPPORTED, it writes NULL to ctx. The context is opaque. The application must not read or write it.
esp_sm3_delete() erases the message bytes and the digest state. Then it frees the context. The handle is not valid after the call. If the application does not call this function, the context stays allocated.
Call esp_sm3_delete() after esp_sm3_finish(). Call it also to abandon an operation.
Concurrency
esp_sm3_update() and esp_sm3_finish() acquire the SHA peripheral. They hold it only while the hardware processes a message block, and they release it before they return. esp_sm3_create() and esp_sm3_delete() never touch the peripheral.
esp_sm3_update() acquires the peripheral only when the new bytes complete at least one 64-byte block. A call with fewer bytes copies them into the context and returns. esp_sm3_finish() always acquires the peripheral, because the padding completes the last block.
An operation can therefore stay open for a long time at no cost to other users of the peripheral. Operations with different contexts can run in parallel from different tasks.
Do not use one context from two tasks at the same time.
API Reference
Header File
This header file can be included with:
#include "esp_sm3.h"
This header file is a part of the API provided by the
esp_securitycomponent. To declare that your component depends onesp_security, add the following to your CMakeLists.txt:REQUIRES esp_security
or
PRIV_REQUIRES esp_security
Functions
-
esp_err_t esp_sm3_create(esp_sm3_ctx_handle_t *ctx)
Start a new SM3 operation.
The function allocates the context. Call esp_sm3_delete() to release it.
- Parameters:
ctx -- [out] Receives the handle of the new context. The function writes NULL if it returns ESP_ERR_NO_MEM or ESP_ERR_NOT_SUPPORTED.
- Returns:
ESP_OK on success
ESP_ERR_INVALID_ARG if ctx is NULL
ESP_ERR_NO_MEM if the allocation fails
ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions
-
esp_err_t esp_sm3_update(esp_sm3_ctx_handle_t ctx, const void *input, size_t ilen)
Add message bytes to an SM3 operation.
Call this function as many times as necessary. The function acquires the SHA peripheral only when the new bytes complete at least one 64-byte block. It releases the peripheral before it returns.
- Parameters:
ctx -- Context from esp_sm3_create().
input -- Message bytes. Can be NULL if ilen is 0.
ilen -- Number of message bytes.
- Returns:
ESP_OK on success
ESP_ERR_INVALID_ARG if ctx is NULL, or if input is NULL and ilen is not 0
ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions
-
esp_err_t esp_sm3_finish(esp_sm3_ctx_handle_t ctx, uint8_t *output, size_t olen)
Complete an SM3 operation and read the digest.
The function always acquires the SHA peripheral, because the padding completes the last message block. It releases the peripheral before it returns.
- Parameters:
ctx -- Context from esp_sm3_create().
output -- Buffer for the digest.
olen -- Size of output in bytes. Must be ESP_SM3_DIGEST_LEN or more.
- Returns:
ESP_OK on success
ESP_ERR_INVALID_ARG if ctx or output is NULL
ESP_ERR_INVALID_SIZE if olen is too small
ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions
-
void esp_sm3_delete(esp_sm3_ctx_handle_t ctx)
Erase and release an SM3 context.
The function erases the message bytes and the digest state. Then it frees the context. Call this function after esp_sm3_finish(), and also to abandon an operation. The handle is not valid after the call. If you do not call this function, the context stays allocated.
- Parameters:
ctx -- Context from esp_sm3_create(). The function accepts NULL.
-
esp_err_t esp_sm3(const void *input, size_t ilen, uint8_t *output, size_t olen)
Compute the SM3 digest of one buffer.
- Parameters:
input -- Message bytes. Can be NULL if ilen is 0.
ilen -- Number of message bytes.
output -- Buffer for the digest.
olen -- Size of output in bytes. Must be ESP_SM3_DIGEST_LEN or more.
- Returns:
ESP_OK on success
ESP_ERR_INVALID_ARG if output is NULL, or if input is NULL and ilen is not 0
ESP_ERR_INVALID_SIZE if olen is too small
ESP_ERR_NOT_SUPPORTED if an eFuse disables the SM crypto functions
Macros
-
ESP_SM3_DIGEST_LEN
Length of an SM3 digest in bytes.
-
ESP_SM3_BLOCK_LEN
Size of an SM3 message block in bytes.
Type Definitions
-
typedef struct esp_sm3_ctx_s *esp_sm3_ctx_handle_t
Handle of one SM3 operation.
esp_sm3_create() allocates the context. esp_sm3_delete() releases it. Do not read or write the context.