Reuse authenticated immutable RS subsets for playback reads
This commit is contained in:
1 parent
2fac28b7e9
commit
4ae8fc7c45
2 files changed
+21
-3
No files matched your search
@@ -27,6 +27,8 @@ struct stream_cached_batch {
|
|||||||
uint16_t count;
|
uint16_t count;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
int rejected;
|
int rejected;
|
||||||
|
int verified;
|
||||||
|
uint8_t verified_parts[(RS_MAX_BLOCKS + 7) / 8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stream_buffer {
|
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;
|
return STREAM_ERR_ARGUMENT;
|
||||||
}
|
}
|
||||||
const uint8_t *blocks[RS_MAX_BLOCKS] = {0};
|
const uint8_t *blocks[RS_MAX_BLOCKS] = {0};
|
||||||
for (uint32_t slot = batch->first_slot; slot != STREAM_SLOT_NONE; slot = b->slots[slot].next)
|
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;
|
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);
|
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) {
|
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);
|
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,
|
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};
|
.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_OK) {
|
||||||
if (result != STREAM_ERR_SIGNATURE && result != STREAM_ERR_FORMAT) return result;
|
if (result != STREAM_ERR_SIGNATURE && result != STREAM_ERR_FORMAT) return result;
|
||||||
batch->rejected = 1; b->stats.rejected_batches++;
|
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;
|
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);
|
memcpy(output, b->decode_output + STREAM_BATCH_HEADER, batch->data_length);
|
||||||
*length = 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);
|
DEBUG_TRACE(DEBUG_CATEGORY_STREAM, "buffer decoded seq=%llu present=%u length=%u", (unsigned long long)seq, batch->count, batch->data_length);
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ int stream_buffer_read(struct stream_buffer *buffer, uint64_t seq, uint8_t subbl
|
|||||||
int stream_buffer_range(struct stream_buffer *buffer, uint8_t subblock, uint64_t *first, uint64_t *last);
|
int stream_buffer_range(struct stream_buffer *buffer, uint8_t subblock, uint64_t *first, uint64_t *last);
|
||||||
|
|
||||||
/* Восстановить пачку и проверить одну подпись; достаточно capacity >= действительной длины.
|
/* Восстановить пачку и проверить одну подпись; достаточно capacity >= действительной длины.
|
||||||
|
* После успеха фиксируется использованный набор k неизменяемых частей: повторное чтение не проверяет подпись заново
|
||||||
|
* и не доверяет поздним частям, которые не участвовали в подтверждённом восстановлении.
|
||||||
* STREAM_REJECTED означает неверную подпись/подписанные метаданные; такая пачка повторно не декодируется.
|
* STREAM_REJECTED означает неверную подпись/подписанные метаданные; такая пачка повторно не декодируется.
|
||||||
* Выход не меняется при WAIT/GAP/EXPIRED/REJECTED/ошибке; отсутствующие части в кольцо не добавляются. */
|
* Выход не меняется при WAIT/GAP/EXPIRED/REJECTED/ошибке; отсутствующие части в кольцо не добавляются. */
|
||||||
int stream_buffer_decode(struct stream_buffer *buffer, uint64_t seq, uint8_t *output, size_t capacity, size_t *length);
|
int stream_buffer_decode(struct stream_buffer *buffer, uint64_t seq, uint8_t *output, size_t capacity, size_t *length);
|
||||||
|
|||||||
Reference in new issue
Block a user