Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_blake3.c
Go to the documentation of this file.
1#ifdef HAVE_BLAKE3
2
3#include "cx_blake3_ref.h"
4#include "cx_utils.h"
5#include "cx_ram.h"
6
7#include <string.h>
8
13cx_err_t cx_blake3_init_default(cx_blake3_t *hash)
14{
15 blake3_init_ctx(hash, IV, 0);
16 return CX_OK;
17}
18
22cx_err_t cx_blake3_init_keyed(cx_blake3_t *hash, const uint8_t *key)
23{
24 uint32_t key_words[BLAKE3_NB_OF_WORDS];
25 load_key_words(key, key_words);
26 blake3_init_ctx(hash, key_words, KEYED_HASH);
27 return CX_OK;
28}
29
35cx_err_t cx_blake3_init_derive_key(cx_blake3_t *hash, const void *context, size_t context_len)
36{
37 uint8_t context_key[BLAKE3_KEY_LEN];
38 uint32_t context_key_words[BLAKE3_NB_OF_WORDS];
39 cx_err_t error;
40
41 // The context string context is hashed with the key words set to IV_0,...,IV_7
42 // The DERIVE_KEY_CONTEXT flag is set for every compression
43 // Then the key material context_key_words is hashed with the key words set to the
44 // the first 8 output words of the first stage (context_key)
45
46 blake3_init_ctx(hash, IV, DERIVE_KEY_CONTEXT);
47 CX_CHECK(cx_blake3_update(hash, context, context_len));
48 CX_CHECK(cx_blake3_final(hash, context_key, BLAKE3_KEY_LEN));
49 load_key_words(context_key, context_key_words);
50 blake3_init_ctx(hash, context_key_words, DERIVE_KEY_MATERIAL);
51end:
52 return error;
53}
54
55cx_err_t cx_blake3_init(cx_blake3_t *hash,
56 uint8_t mode,
57 const uint8_t *key,
58 const void *context,
59 size_t context_len)
60{
61 switch (mode) {
62 case 0:
63 cx_blake3_init_default(hash);
64 break;
65 case KEYED_HASH:
66 if (NULL == key) {
67 return CX_INVALID_PARAMETER;
68 }
69 cx_blake3_init_keyed(hash, key);
70 break;
71 case DERIVE_KEY_CONTEXT:
72 if ((NULL == context) || (!context_len)) {
73 return CX_INVALID_PARAMETER;
74 }
75 cx_blake3_init_derive_key(hash, context, context_len);
76 break;
77 default:
78 return CX_INVALID_PARAMETER;
79 }
80 return CX_OK;
81}
82
83cx_err_t cx_blake3_update(cx_blake3_t *hash, const void *input, size_t input_len)
84{
85 const uint8_t *input_bytes = (const uint8_t *) input;
86 size_t state_len;
87 size_t nb_bytes;
88
89 if (!input_len) {
90 return CX_OK;
91 }
92
93 state_len = BLAKE3_BLOCK_LEN * (hash->chunk).blocks_compressed + (hash->chunk).buffer_len;
94
95 if (state_len > 0) {
96 nb_bytes = BLAKE3_CHUNK_LEN - state_len;
97 if (nb_bytes > input_len) {
98 nb_bytes = input_len;
99 }
100 blake3_state_update(&hash->chunk, input_bytes, nb_bytes);
101 input_bytes += nb_bytes;
102 input_len -= nb_bytes;
103
104 if (input_len > 0) {
105 cx_blake3_state_out_t output = blake3_state_output(&hash->chunk);
106 uint8_t chunk_cv[32];
107 blake3_output_chain(&output, chunk_cv);
108 blake3_hasher_push_cv(hash, chunk_cv, (hash->chunk).t);
109 blake3_state_reset(&hash->chunk, hash->key, (hash->chunk).t + 1);
110 }
111 else {
112 return CX_OK;
113 }
114 }
115
116 while (input_len > BLAKE3_CHUNK_LEN) {
117 size_t subtree_len;
118 uint64_t count;
119 uint64_t subtree_chunks;
120 subtree_len = 1ULL << highest_one(input_len | 1);
121 count = (hash->chunk).t * BLAKE3_CHUNK_LEN;
122
123 while ((((uint64_t) (subtree_len - 1)) & count) != 0) {
124 subtree_len /= 2;
125 }
126
127 subtree_chunks = subtree_len / BLAKE3_CHUNK_LEN;
128 if (subtree_len <= BLAKE3_CHUNK_LEN) {
129 cx_blake3_state_t chunk_state;
130 uint8_t cv[BLAKE3_OUT_LEN];
131 blake3_state_init(&chunk_state, hash->key, (hash->chunk).d);
132 chunk_state.t = (hash->chunk).t;
133 blake3_state_update(&chunk_state, input_bytes, subtree_len);
134 cx_blake3_state_out_t output = blake3_state_output(&chunk_state);
135 blake3_output_chain(&output, cv);
136 blake3_hasher_push_cv(hash, cv, chunk_state.t);
137 }
138 else {
139 uint8_t cv_pair[2 * BLAKE3_OUT_LEN];
140 blake3_compress_subtree_to_parent(
141 input_bytes, subtree_len, hash->key, (hash->chunk).t, (hash->chunk).d, cv_pair);
142 blake3_hasher_push_cv(hash, cv_pair, (hash->chunk).t);
143 blake3_hasher_push_cv(
144 hash, cv_pair + BLAKE3_OUT_LEN, (hash->chunk).t + (subtree_chunks / 2));
145 }
146 (hash->chunk).t += subtree_chunks;
147 input_bytes += subtree_len;
148 input_len -= subtree_len;
149 }
150
151 if (input_len > 0) {
152 blake3_state_update(&hash->chunk, input_bytes, input_len);
153 blake3_hasher_merge_cv(hash, (hash->chunk).t);
154 }
155 return CX_OK;
156}
157
158cx_err_t cx_blake3_final(cx_blake3_t *hash, uint8_t *output, size_t out_len)
159{
160 if (!out_len) {
161 return CX_INVALID_PARAMETER;
162 }
163 cx_blake3_state_out_t chunk_out;
164
165 // If the subtree stack is empty, then the current chunk is the root.
166 if (!hash->cv_stack_len) {
167 chunk_out = blake3_state_output(&hash->chunk);
168 blake3_output_root_bytes(&chunk_out, output, out_len);
169 return CX_OK;
170 }
171
172 size_t cvs_remaining;
173 size_t state_len
174 = BLAKE3_BLOCK_LEN * (hash->chunk).blocks_compressed + (hash->chunk).buffer_len;
175 uint8_t parent_block[BLAKE3_BLOCK_LEN];
176
177 if (state_len > 0) {
178 cvs_remaining = hash->cv_stack_len;
179 chunk_out = blake3_state_output(&hash->chunk);
180 }
181 else {
182 // There are always at least 2 CVs in the stack in this case.
183 cvs_remaining = hash->cv_stack_len - 2;
184 memcpy(chunk_out.input_cv, hash->key, BLAKE3_OUT_LEN);
185 memcpy(chunk_out.block, hash->cv_stack + cvs_remaining * BLAKE3_OUT_LEN, BLAKE3_BLOCK_LEN);
186 chunk_out.block_len = BLAKE3_BLOCK_LEN;
187 chunk_out.counter = 0;
188 chunk_out.d = (hash->chunk).d | PARENT;
189 }
190 while (cvs_remaining > 0) {
191 cvs_remaining -= 1;
192 memcpy(parent_block, hash->cv_stack + cvs_remaining * BLAKE3_OUT_LEN, BLAKE3_OUT_LEN);
193 blake3_output_chain(&chunk_out, parent_block + BLAKE3_OUT_LEN);
194 memcpy(chunk_out.input_cv, hash->key, BLAKE3_OUT_LEN);
195 memcpy(chunk_out.block, parent_block, BLAKE3_BLOCK_LEN);
196 chunk_out.block_len = BLAKE3_BLOCK_LEN;
197 chunk_out.counter = 0;
198 chunk_out.d = (hash->chunk).d | PARENT;
199 }
200 blake3_output_root_bytes(&chunk_out, output, out_len);
201
202 return CX_OK;
203}
204
205static bool cx_blake3_validate_context(const cx_blake3_t *hash)
206{
207 if ((NULL == hash) || !hash->is_init) {
208 return false;
209 }
210 return true;
211}
212
213cx_err_t cx_blake3(cx_blake3_t *hash,
214 uint8_t mode,
215 const void *input,
216 size_t input_len,
217 uint8_t *out,
218 size_t out_len)
219{
220 cx_err_t error;
221 // Check the context
222 if (!cx_blake3_validate_context(hash)) {
223 return CX_INTERNAL_ERROR;
224 }
225 CX_CHECK(cx_blake3_update(hash, input, input_len));
226
227 if (mode & LAST) {
228 CX_CHECK(cx_blake3_final(hash, out, out_len));
229 }
230end:
231 return error;
232}
233
234#endif // HAVE_BLAKE3
unsigned char uint8_t
Definition usbd_conf.h:53