跳到主要内容

pico-sha256

SHA-256 硬件加速实现。

详细说明

RP2350 内置了 SHA-256 哈希算法的硬件加速实现,其速度远快于软件实现的 SHA-256 校验运算。

pico_sha256_state_t state;
if (pico_sha256_try_start(&state, SHA256_BIG_ENDIAN, true) == PICO_OK) {
sha256_result_t result;
pico_sha256_update(&state, some_data, sizeof(some_data));
pico_sha256_update(&state, some_more_data, sizeof(some_more_data));
pico_sha256_finish(&state, &result);
for (int i = 0; i < SHA256_RESULT_BYTES; i++) {
printf("%02x", result.bytes[i]);
}
}

示例

hello_sha256.c
#include <stdio.h>
#include <string.h>
// Include sys/types.h before inttypes.h to work around issue with
// certain versions of GCC and newlib which causes omission of PRIu64
#include <sys/types.h>
#include <inttypes.h>
#include <stdlib.h>

#include "pico/stdlib.h"
#include "pico/sha256.h"

// This was generated by cmake from sample.txt.inc
#include "sample.txt.inc"

static void sha_example() {
printf("Text: %d bytes\n", sizeof(sample_txt) - 1);
for(int i = 0; i < sizeof(sample_txt) - 1; i++) {
if (i > 0 && i % 128 == 0) printf("\n");
putchar(sample_txt[i]);
}
printf("\n");

// Allocate a state object and start the calculation
pico_sha256_state_t state;
int rc = pico_sha256_start_blocking(&state, SHA256_BIG_ENDIAN, true); // using some DMA system resources
hard_assert(rc == PICO_OK);
pico_sha256_update_blocking(&state, (const uint8_t*)sample_txt, sizeof(sample_txt) - 1);

// Get the result of the sha256 calculation
sha256_result_t result;
pico_sha256_finish(&state, &result);

// print resulting sha256 result
printf("Result:\n");
for(int i = 0; i < SHA256_RESULT_BYTES; i++) {
printf("%02x ", result.bytes[i]);
if ((i+1) % 16 == 0) printf("\n");
}

// check it's what we expect from "sha256sum sample.txt"
const uint8_t sha_expected[SHA256_RESULT_BYTES] = {
0x2d, 0x8c, 0x2f, 0x6d, 0x97, 0x8c, 0xa2, 0x17, 0x12, 0xb5, 0xf6, 0xde, 0x36, 0xc9, 0xd3, 0x1f,
0xa8, 0xe9, 0x6a, 0x4f, 0xa5, 0xd8, 0xff, 0x8b, 0x01, 0x88, 0xdf, 0xb9, 0xe7, 0xc1, 0x71, 0xbb
};
hard_assert(memcmp(sha_expected, &result, SHA256_RESULT_BYTES) == 0);
}

#define BUFFER_SIZE 10000

// A performance test with a large amount of data
static void nist_test(bool use_dma) {
// nist 3
uint8_t *buffer = malloc(BUFFER_SIZE);
memset(buffer, 0x61, BUFFER_SIZE);
const uint8_t nist_3_expected[] = { \
0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67,
0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 };

uint64_t start = time_us_64();
pico_sha256_state_t state;
int rc = pico_sha256_start_blocking(&state, SHA256_BIG_ENDIAN, use_dma); // call start once
hard_assert(rc == PICO_OK);
for(int i = 0; i < 1000000; i += BUFFER_SIZE) {
pico_sha256_update_blocking(&state, buffer, BUFFER_SIZE); // call update as many times as required
}
sha256_result_t result;
pico_sha256_finish(&state, &result); // Call finish when done to get the result

// Display the time taken
uint64_t pico_time = time_us_64() - start;
printf("Time for sha256 of 1M bytes %s DMA %"PRIu64"ms\n", use_dma ? "with" : "without", pico_time / 1000);
hard_assert(memcmp(nist_3_expected, result.bytes, SHA256_RESULT_BYTES) == 0);
}

int main() {
stdio_init_all();

sha_example();

// performance test with and without DMA
nist_test(false);
nist_test(true);

printf("Success\n");
}

类型定义

  • `typedef struct pico_sha256_state pico_sha256_state_t``: API 使用的 SHA-256 状态。

函数

void pico_sha256_cleanup (pico_sha256_state_t *state)
 释放 SHA-256 硬件上的内部锁。

int pico_sha256_try_start (pico_sha256_state_t *state, enum sha256_endianness endianness, bool use_dma)
 启动 SHA-256 计算,若 SHA-256 硬件不可用则立即返回错误。

int pico_sha256_start_blocking_until (pico_sha256_state_t *state, enum sha256_endianness endianness, bool use_dma, absolute_time_t until)
 启动 SHA-256 计算,在指定时间内等待 SHA-256 硬件可用。

static int pico_sha256_start_blocking (pico_sha256_state_t *state, enum sha256_endianness endianness, bool use_dma)
 启动 SHA-256 计算,永久阻塞等待直到 SHA-256 硬件可用。

void pico_sha256_update (pico_sha256_state_t **state, const uint8_t **data, size_t data_size_bytes)
 向 SHA-256 计算中添加字节数据。

void pico_sha256_update_blocking (pico_sha256_state_t **state, const uint8_t **data, size_t data_size_bytes)
 向 SHA-256 计算中添加字节数据(阻塞版本)。

void pico_sha256_finish (pico_sha256_state_t **state, sha256_result_t **out)
 完成 SHA-256 计算并返回结果。

类型定义文档

pico_sha256_state_t

typedef struct pico_sha256_state pico_sha256_state_t

API 使用的 SHA-256 状态。

函数文档

pico_sha256_cleanup

void pico_sha256_cleanup (pico_sha256_state_t * state)

释放 SHA-256 硬件上的内部锁。

释放 SHA-256 硬件上的内部锁。若内部锁未被申请,则此函数无操作。

参数

  • state: 指向 pico_sha256_state_t 实例的指针

pico_sha256_finish

void pico_sha256_finish (pico_sha256_state_t ** state, sha256_result_t ** out)`

完成 SHA-256 计算并返回结果。

结束 SHA-256 计算,释放硬件供其他调用方使用。必须已调用 pico_sha256_try_start。

参数

  • state: 指向 pico_sha256_state_t 实例的指针
  • out: SHA-256 校验和

pico_sha256_start_blocking

static int pico_sha256_start_blocking (pico_sha256_state_t * state, enum sha256_endianness endianness, bool use_dma) [inline], [static]`

启动 SHA-256 计算,永久阻塞等待直到 SHA-256 硬件可用。

初始化硬件和状态,准备开始新的 SHA-256 计算。同一时间只能启动一个实例。

参数

  • state: 指向 pico_sha256_state_t 实例的指针
  • endianness: SHA256_BIG_ENDIAN 或 SHA256_LITTLE_ENDIAN,用于数据输入和输出
  • use_dma: 设为 true 以在内部使用 DMA 将数据复制到硬件,速度更快但会占用 DMA 硬件资源

返回值

若硬件可用且 SHA-256 计算可以启动,则返回 PICO_OK,否则返回错误码

pico_sha256_start_blocking_until

int pico_sha256_start_blocking_until (pico_sha256_state_t * state, enum sha256_endianness endianness, bool use_dma, absolute_time_t until)`

启动 SHA-256 计算,在指定时间内等待 SHA-256 硬件可用。

初始化硬件和状态,准备开始新的 SHA-256 计算。同一时间只能启动一个实例。

参数

  • state: 指向 pico_sha256_state_t 实例的指针
  • endianness: SHA256_BIG_ENDIAN 或 SHA256_LITTLE_ENDIAN,用于数据输入和输出
  • use_dma: 设为 true 以在内部使用 DMA 将数据复制到硬件,速度更快但会占用 DMA 硬件资源
  • until: 等待 SHA 硬件可用的最长时间

返回值

若硬件在规定时间内可用且 SHA-256 计算可以启动,则返回 PICO_OK,否则返回错误码

pico_sha256_try_start

int pico_sha256_try_start (pico_sha256_state_t * state, enum sha256_endianness endianness, bool use_dma)`

启动 SHA-256 计算,若 SHA-256 硬件不可用则立即返回错误。

初始化硬件和状态,准备开始新的 SHA-256 计算。同一时间只能启动一个实例。

参数

  • state: 指向 pico_sha256_state_t 实例的指针
  • endianness: SHA256_BIG_ENDIAN 或 SHA256_LITTLE_ENDIAN,用于数据输入和输出
  • use_dma: 设为 true 以在内部使用 DMA 将数据复制到硬件,速度更快但会占用 DMA 硬件资源

返回值

若硬件可用且 SHA-256 计算可以启动,则返回 PICO_OK,否则返回错误码

pico_sha256_update

void pico_sha256_update (pico_sha256_state_t ** state, const uint8_t ** data, size_t data_size_bytes)`

向 SHA-256 计算中添加字节数据。

向 SHA-256 计算中添加字节数据。可根据需要多次调用以添加所有数据。必须已调用 pico_sha256_try_start(或等效函数)。

参数

  • state: 指向 pico_sha256_state_t 实例的指针
  • data: 指向要添加到计算中的数据的指针
  • data_size_bytes: 要添加的数据量

此函数可能在复制完成前返回,此时传入的数据必须保持有效且不变,直到下一次调用 pico_sha256_update 或 pico_sha256_finish。若未遵守此要求,可能导致 SHA-256 计算使用损坏的数据,产生意外结果。

pico_sha256_update_blocking

void pico_sha256_update_blocking (pico_sha256_state_t ** state, const uint8_t ** data, size_t data_size_bytes)`

向 SHA-256 计算中添加字节数据(阻塞版本)。

向 SHA-256 计算中添加字节数据。可根据需要多次调用以添加所有数据。必须已调用 pico_sha256_try_start。

参数

  • state: 指向 pico_sha256_state_t 实例的指针
  • data: 指向要添加到计算中的数据的指针
  • data_size_bytes: 要添加的数据量

此函数仅在不再需要传入数据后才会返回,因此返回后可安全释放或修改数据。


中文翻译版以英文版相同知识授权方式共享:CC-BY-SA 4.0。交流 Q群:498908352