1
6
7
16
17
18
19
20
26
27
32
33
34
35
36
37
38
39
43
44
45
46
47
48
49
52
53
54
55
56
57
58
59
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
107
108
109
110
111
112
113
114
120
121
125
126
127
136
137
140
141
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* ... */
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "hardware/sha256.h"
#include "pico/bootrom/lock.h"
#include "pico/sha256.h"
#include "pico/time.h"
7 includes
#define SHA256_PADDING_DATA_BYTES 9
#define SHA256_BLOCK_SIZE_BYTES 64
bool __weak pico_sha256_lock(pico_sha256_state_t *state) {
if (!bootrom_try_acquire_lock(BOOTROM_LOCK_SHA_256))
return false;
state->locked = true;
return true;
}{ ... }
void __weak pico_sha256_unlock(pico_sha256_state_t *state) {
assert(state->locked);
bootrom_release_lock(BOOTROM_LOCK_SHA_256);
state->locked = false;
}{ ... }
int pico_sha256_try_start(pico_sha256_state_t *state, enum sha256_endianness endianness, bool use_dma) {
memset(state, 0, sizeof(*state));
if (!pico_sha256_lock(state)) return PICO_ERROR_RESOURCE_IN_USE;
state->endianness = endianness;
if (use_dma) {
state->channel = (int8_t)dma_claim_unused_channel(false);
if (state->channel < 0) {
pico_sha256_unlock(state);
return PICO_ERROR_INSUFFICIENT_RESOURCES;
}if (state->channel < 0) { ... }
state->config = dma_channel_get_default_config(state->channel);
channel_config_set_transfer_data_size(&state->config, DMA_SIZE_8);
channel_config_set_read_increment(&state->config, true);
channel_config_set_write_increment(&state->config, false);
channel_config_set_dreq(&state->config, DREQ_SHA256);
sha256_set_dma_size(1);
}if (use_dma) { ... } else {
state->channel = -1;
}else { ... }
sha256_err_not_ready_clear();
sha256_set_bswap(endianness == SHA256_BIG_ENDIAN);
sha256_start();
state->total_data_size = 0;
return PICO_OK;
}{ ... }
int pico_sha256_start_blocking_until(pico_sha256_state_t *state, enum sha256_endianness endianness, bool use_dma, absolute_time_t until) {
int rc;
do {
rc = pico_sha256_try_start(state, endianness, use_dma);
if (rc != PICO_ERROR_RESOURCE_IN_USE) break;
if (time_reached(until)) {
rc = PICO_ERROR_TIMEOUT;
break;
}if (time_reached(until)) { ... }
...} while (true);
return rc;
}{ ... }
static void write_to_hardware(pico_sha256_state_t *state, const uint8_t *data, size_t data_size_bytes) {
if (state->channel >= 0) {
dma_channel_wait_for_finish_blocking(state->channel);
assert(!sha256_err_not_ready());
sha256_wait_ready_blocking();
dma_channel_configure(
state->channel,
&state->config,
sha256_get_write_addr(),
data,
data_size_bytes,
true
);
}if (state->channel >= 0) { ... } else {
if (!state->cache_used && !(((uintptr_t)data)&3u)) {
GCC_Like_Pragma("GCC diagnostic ignored \"-Wcast-align\"")
const uint32_t *data32 = (const uint32_t *)data;
while (data_size_bytes >= 4) {
sha256_wait_ready_blocking();
sha256_put_word(*data32++);
data_size_bytes -= 4;
}while (data_size_bytes >= 4) { ... }
data = (const uint8_t *)data32;
}if (!state->cache_used && !(((uintptr_t)data)&3u)) { ... }
while (data_size_bytes--) {
state->cache.bytes[state->cache_used++] = *data++;
if (state->cache_used == 4) {
state->cache_used = 0;
sha256_wait_ready_blocking();
sha256_put_word(state->cache.word);
}if (state->cache_used == 4) { ... }
}while (data_size_bytes--) { ... }
}else { ... }
}{ ... }
static void update_internal(pico_sha256_state_t *state, const uint8_t *data, size_t data_size_bytes) {
assert(state->locked);
size_t bytes_left = ((state->total_data_size + (SHA256_BLOCK_SIZE_BYTES - 1)) & ~(SHA256_BLOCK_SIZE_BYTES - 1)) - state->total_data_size;
if (bytes_left > data_size_bytes) bytes_left = data_size_bytes;
if (bytes_left > 0) {
write_to_hardware(state, data, bytes_left);
state->total_data_size += bytes_left;
data_size_bytes -= bytes_left;
data += bytes_left;
}if (bytes_left > 0) { ... }
if (data_size_bytes > 0) {
write_to_hardware(state, data, data_size_bytes);
state->total_data_size += data_size_bytes;
}if (data_size_bytes > 0) { ... }
}{ ... }
static void add_zero_bytes(pico_sha256_state_t *state, size_t data_size_bytes) {
uint32_t zero = 0;
assert(data_size_bytes < INT32_MAX);
while((int32_t)data_size_bytes > 0) {
update_internal(state, (uint8_t *)&zero, MIN(4, data_size_bytes));
data_size_bytes -= 4;
}while ((int32_t)data_size_bytes > 0) { ... }
}{ ... }
void pico_sha256_update(pico_sha256_state_t *state, const uint8_t *data, size_t data_size_bytes) {
update_internal(state, data, data_size_bytes);
}{ ... }
void pico_sha256_update_blocking(pico_sha256_state_t *state, const uint8_t *data, size_t data_size_bytes) {
update_internal(state, data, data_size_bytes);
if (state->channel >= 0) {
dma_channel_wait_for_finish_blocking(state->channel);
}if (state->channel >= 0) { ... }
}{ ... }
static void write_padding(pico_sha256_state_t *state) {
uint64_t size = (state->total_data_size + SHA256_PADDING_DATA_BYTES + (SHA256_BLOCK_SIZE_BYTES - 1)) & ~(SHA256_BLOCK_SIZE_BYTES - 1);
const size_t user_data_size = state->total_data_size;
const size_t padding_size_bytes = size - state->total_data_size;
const uint8_t one_bit = 0x80;
update_internal(state, &one_bit, 1);
add_zero_bytes(state, padding_size_bytes - SHA256_PADDING_DATA_BYTES);
size = __builtin_bswap64(user_data_size * 8);
update_internal(state, (uint8_t*)&size, sizeof(uint64_t));
}{ ... }
void pico_sha256_finish(pico_sha256_state_t *state, sha256_result_t *out) {
assert(state->locked);
if (out) {
write_padding(state);
if (state->channel >= 0) {
dma_channel_wait_for_finish_blocking(state->channel);
assert(!sha256_err_not_ready());
}if (state->channel >= 0) { ... }
sha256_wait_valid_blocking();
sha256_get_result(out, state->endianness);
}if (out) { ... }
if (state->channel >= 0) {
dma_channel_cleanup(state->channel);
dma_channel_unclaim(state->channel);
state->channel = -1;
}if (state->channel >= 0) { ... }
pico_sha256_unlock(state);
}{ ... }