Frame arithmetic is daemon-gated with its only consumers; boundary tests are finite
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d281343dc9
commit
bf07b2cd38
2 changed files with 15 additions and 9 deletions
|
|
@ -29,6 +29,7 @@ pub struct TransportEnvelope {
|
|||
|
||||
/// The longest caller id, request id or model name a service admits. The
|
||||
/// frame arithmetic below depends on it, so a longer one is refused up front.
|
||||
#[cfg(feature = "daemon")]
|
||||
pub(crate) const MAX_IDENTITY_BYTES: usize = 256;
|
||||
|
||||
/// The most bytes a serialized envelope holding `ciphertext_len` ciphertext
|
||||
|
|
@ -36,6 +37,7 @@ pub(crate) const MAX_IDENTITY_BYTES: usize = 256;
|
|||
/// array of integers: a byte of 128 or more takes two bytes, so the worst case
|
||||
/// is twice the ciphertext, plus the array header and the envelope's other
|
||||
/// fields at their longest. Measured from the real encoding, not assumed.
|
||||
#[cfg(feature = "daemon")]
|
||||
pub(crate) fn worst_frame_bytes(ciphertext_len: usize) -> usize {
|
||||
let shell = rmp_serde::to_vec(&TransportEnvelope {
|
||||
schema_id: ENVELOPE_SCHEMA_ID.to_string(),
|
||||
|
|
@ -429,6 +431,7 @@ mod tests {
|
|||
assert!(matches!(write(&[], 1_000), Err(TransportFrameError::Size)));
|
||||
}
|
||||
|
||||
#[cfg(feature = "daemon")]
|
||||
#[test]
|
||||
fn the_worst_frame_is_the_real_encoding_of_an_all_high_ciphertext() {
|
||||
let long = "x".repeat(MAX_IDENTITY_BYTES);
|
||||
|
|
@ -449,6 +452,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "daemon")]
|
||||
#[test]
|
||||
fn a_sealed_envelope_never_exceeds_the_worst_frame_for_its_ciphertext() {
|
||||
let key = security("epiphany-distinct-test-key");
|
||||
|
|
|
|||
|
|
@ -917,16 +917,21 @@ mod tests {
|
|||
assert_eq!(executions, 1);
|
||||
}
|
||||
|
||||
/// The largest result plaintext whose sealed frame fits at the worst encoding.
|
||||
fn widest_guaranteed_plaintext(base: usize) -> usize {
|
||||
(base..=FRAME)
|
||||
.take_while(|plaintext| worst_frame_bytes(plaintext + GCM_TAG) <= FRAME)
|
||||
.last()
|
||||
.unwrap_or(base)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_result_within_what_the_worst_encoding_leaves_is_delivered_intact() {
|
||||
// The largest plaintext whose sealed frame fits at the worst encoding is
|
||||
// always carried, whatever the ciphertext bytes turn out to be.
|
||||
for request_id in id_cases() {
|
||||
let base = empty_result_len(&request_id);
|
||||
let mut plaintext = base;
|
||||
while worst_frame_bytes(plaintext + 1 + GCM_TAG) <= FRAME {
|
||||
plaintext += 1;
|
||||
}
|
||||
let plaintext = widest_guaranteed_plaintext(base);
|
||||
let (first, second, _) = call_twice(SizedBackend::new(plaintext - base), &request_id);
|
||||
let TransportDisposition::Transported { events, receipt } = &first.disposition else {
|
||||
panic!("expected a transported result");
|
||||
|
|
@ -946,11 +951,8 @@ mod tests {
|
|||
// way the caller gets an answer, and the retry gets the same one.
|
||||
for request_id in id_cases() {
|
||||
let base = empty_result_len(&request_id);
|
||||
let mut plaintext = base;
|
||||
while worst_frame_bytes(plaintext + GCM_TAG) <= FRAME {
|
||||
plaintext += 1;
|
||||
}
|
||||
for extra in [0, 1, 2] {
|
||||
let plaintext = widest_guaranteed_plaintext(base);
|
||||
for extra in [1, 2, 3] {
|
||||
let backend = SizedBackend::new(plaintext + extra - base);
|
||||
let (first, second, executions) = call_twice(backend, &request_id);
|
||||
assert_eq!(first, second);
|
||||
|
|
|
|||
Loading…
Reference in a new issue