13 cx_err_t cx_blake3_init_default(cx_blake3_t *hash)
15 blake3_init_ctx(hash, IV, 0);
22 cx_err_t cx_blake3_init_keyed(cx_blake3_t *hash,
const uint8_t *key)
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);
35 cx_err_t cx_blake3_init_derive_key(cx_blake3_t *hash,
const void *context,
size_t context_len)
37 uint8_t context_key[BLAKE3_KEY_LEN];
38 uint32_t context_key_words[BLAKE3_NB_OF_WORDS];
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);
55 cx_err_t cx_blake3_init(cx_blake3_t *hash,
63 cx_blake3_init_default(hash);
67 return CX_INVALID_PARAMETER;
69 cx_blake3_init_keyed(hash, key);
71 case DERIVE_KEY_CONTEXT:
72 if ((NULL == context) || (!context_len)) {
73 return CX_INVALID_PARAMETER;
75 cx_blake3_init_derive_key(hash, context, context_len);
78 return CX_INVALID_PARAMETER;
83 cx_err_t cx_blake3_update(cx_blake3_t *hash,
const void *input,
size_t input_len)
93 state_len = BLAKE3_BLOCK_LEN * (hash->chunk).blocks_compressed + (hash->chunk).buffer_len;
96 nb_bytes = BLAKE3_CHUNK_LEN - state_len;
97 if (nb_bytes > input_len) {
100 blake3_state_update(&hash->chunk, input_bytes, nb_bytes);
101 input_bytes += nb_bytes;
102 input_len -= nb_bytes;
105 cx_blake3_state_out_t output = blake3_state_output(&hash->chunk);
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);
116 while (input_len > BLAKE3_CHUNK_LEN) {
119 uint64_t subtree_chunks;
120 subtree_len = 1ULL << highest_one(input_len | 1);
121 count = (hash->chunk).t * BLAKE3_CHUNK_LEN;
123 while ((((uint64_t) (subtree_len - 1)) & count) != 0) {
127 subtree_chunks = subtree_len / BLAKE3_CHUNK_LEN;
128 if (subtree_len <= BLAKE3_CHUNK_LEN) {
129 cx_blake3_state_t chunk_state;
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);
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));
146 (hash->chunk).t += subtree_chunks;
147 input_bytes += subtree_len;
148 input_len -= subtree_len;
152 blake3_state_update(&hash->chunk, input_bytes, input_len);
153 blake3_hasher_merge_cv(hash, (hash->chunk).t);
158 cx_err_t cx_blake3_final(cx_blake3_t *hash,
uint8_t *output,
size_t out_len)
161 return CX_INVALID_PARAMETER;
163 cx_blake3_state_out_t chunk_out;
166 if (!hash->cv_stack_len) {
167 chunk_out = blake3_state_output(&hash->chunk);
168 blake3_output_root_bytes(&chunk_out, output, out_len);
172 size_t cvs_remaining;
174 = BLAKE3_BLOCK_LEN * (hash->chunk).blocks_compressed + (hash->chunk).buffer_len;
175 uint8_t parent_block[BLAKE3_BLOCK_LEN];
178 cvs_remaining = hash->cv_stack_len;
179 chunk_out = blake3_state_output(&hash->chunk);
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;
190 while (cvs_remaining > 0) {
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;
200 blake3_output_root_bytes(&chunk_out, output, out_len);
205 static bool cx_blake3_validate_context(
const cx_blake3_t *hash)
207 if ((NULL == hash) || !hash->is_init) {
213 cx_err_t cx_blake3(cx_blake3_t *hash,
222 if (!cx_blake3_validate_context(hash)) {
223 return CX_INTERNAL_ERROR;
225 CX_CHECK(cx_blake3_update(hash, input, input_len));
228 CX_CHECK(cx_blake3_final(hash, out, out_len));