|
|
|
|
@ -27,6 +27,8 @@ struct stream_cached_batch {
|
|
|
|
|
uint16_t count; |
|
|
|
|
uint8_t flags; |
|
|
|
|
int rejected; |
|
|
|
|
int verified; |
|
|
|
|
uint8_t verified_parts[(RS_MAX_BLOCKS + 7) / 8]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct stream_buffer { |
|
|
|
|
@ -419,8 +421,11 @@ int stream_buffer_decode(struct stream_buffer *b, uint64_t seq, uint8_t *output,
|
|
|
|
|
return STREAM_ERR_ARGUMENT; |
|
|
|
|
} |
|
|
|
|
const uint8_t *blocks[RS_MAX_BLOCKS] = {0}; |
|
|
|
|
for (uint32_t slot = batch->first_slot; slot != STREAM_SLOT_NONE; slot = b->slots[slot].next) |
|
|
|
|
blocks[b->slots[slot].subblock] = b->data + slot * b->block_bytes + STREAM_BLOCK_RS_OFF; |
|
|
|
|
for (uint32_t slot = batch->first_slot; slot != STREAM_SLOT_NONE; slot = b->slots[slot].next) { |
|
|
|
|
unsigned sub = b->slots[slot].subblock; |
|
|
|
|
if (!batch->verified || (batch->verified_parts[sub / 8] & (1u << (sub % 8)))) |
|
|
|
|
blocks[sub] = b->data + slot * b->block_bytes + STREAM_BLOCK_RS_OFF; |
|
|
|
|
} |
|
|
|
|
size_t decoded_size = (size_t)(b->descriptor.n - b->descriptor.r) * (batch->block_size - RS_HEADER_SIZE); |
|
|
|
|
if (rs_decode(b->rs, blocks, batch->block_size, b->decode_output, rs_input_capacity(b->rs)) != RS_OK) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "buffer decode RS failed seq=%llu present=%u", (unsigned long long)seq, batch->count); |
|
|
|
|
@ -428,7 +433,8 @@ int stream_buffer_decode(struct stream_buffer *b, uint64_t seq, uint8_t *output,
|
|
|
|
|
} |
|
|
|
|
struct stream_batch_info expected = {.seq = batch->seq, .data_length = batch->data_length, |
|
|
|
|
.timestamp_ms = batch->timestamp_ms, .block_size = batch->block_size, .flags = batch->flags}; |
|
|
|
|
int result = stream_batch_verify(&b->descriptor, b->public_key, &expected, b->decode_output, decoded_size); |
|
|
|
|
int result = batch->verified ? STREAM_OK |
|
|
|
|
: stream_batch_verify(&b->descriptor, b->public_key, &expected, b->decode_output, decoded_size); |
|
|
|
|
if (result != STREAM_OK) { |
|
|
|
|
if (result != STREAM_ERR_SIGNATURE && result != STREAM_ERR_FORMAT) return result; |
|
|
|
|
batch->rejected = 1; b->stats.rejected_batches++; |
|
|
|
|
@ -448,6 +454,16 @@ int stream_buffer_decode(struct stream_buffer *b, uint64_t seq, uint8_t *output,
|
|
|
|
|
} |
|
|
|
|
return STREAM_REJECTED; |
|
|
|
|
} |
|
|
|
|
if (!batch->verified) { |
|
|
|
|
unsigned selected = 0; |
|
|
|
|
for (unsigned sub = 0; sub < b->descriptor.n && selected < (unsigned)(b->descriptor.n - b->descriptor.r); sub++) { |
|
|
|
|
if (!blocks[sub]) continue; |
|
|
|
|
batch->verified_parts[sub / 8] |= (uint8_t)(1u << (sub % 8)); selected++; |
|
|
|
|
} |
|
|
|
|
batch->verified = 1; |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_STREAM, "buffer authenticated immutable RS set source=%llx seq=%llu parts=%u", |
|
|
|
|
(unsigned long long)b->descriptor.source_node_id, (unsigned long long)seq, selected); |
|
|
|
|
} |
|
|
|
|
memcpy(output, b->decode_output + STREAM_BATCH_HEADER, batch->data_length); |
|
|
|
|
*length = batch->data_length; |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_STREAM, "buffer decoded seq=%llu present=%u length=%u", (unsigned long long)seq, batch->count, batch->data_length); |
|
|
|
|
|