use crate::imp::core::serving::concat_output;
use crate::imp::core::Bytes32;
use crate::imp::crypto::sha256;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServingInputs {
pub retrieval_key: Bytes32,
pub roothash: Bytes32,
pub chunk_ciphertext: Vec<Vec<u8>>,
}
impl ServingInputs {
pub fn output_bytes(&self) -> Vec<u8> {
let refs: Vec<&[u8]> = self.chunk_ciphertext.iter().map(|c| c.as_slice()).collect();
concat_output(&refs)
}
pub fn compute_public_output(&self) -> Bytes32 {
let output = self.output_bytes();
let mut preimage = Vec::with_capacity(32 + output.len());
preimage.extend_from_slice(&self.roothash.0);
preimage.extend_from_slice(&output);
sha256(&preimage)
}
}
#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
use super::*;
fn inputs(root: [u8; 32], chunks: Vec<Vec<u8>>) -> ServingInputs {
ServingInputs {
retrieval_key: Bytes32([7u8; 32]),
roothash: Bytes32(root),
chunk_ciphertext: chunks,
}
}
#[test]
fn public_output_binds_roothash_then_ciphertext() {
let inp = inputs([9u8; 32], vec![vec![1, 2, 3], vec![4, 5]]);
let mut preimage = vec![9u8; 32];
preimage.extend_from_slice(&[1, 2, 3, 4, 5]);
assert_eq!(inp.compute_public_output(), sha256(&preimage));
}
#[test]
fn output_bytes_is_concatenated_ciphertext() {
let inp = inputs([0u8; 32], vec![vec![0xDE, 0xAD], vec![0xBE, 0xEF]]);
assert_eq!(inp.output_bytes(), vec![0xDE, 0xAD, 0xBE, 0xEF]);
}
#[test]
fn different_ciphertext_gives_different_output() {
let a = inputs([9u8; 32], vec![vec![1, 2, 3]]);
let b = inputs([9u8; 32], vec![vec![1, 2, 4]]);
assert_ne!(a.compute_public_output(), b.compute_public_output());
}
#[test]
fn different_roothash_gives_different_output() {
let a = inputs([9u8; 32], vec![vec![1, 2, 3]]);
let b = inputs([8u8; 32], vec![vec![1, 2, 3]]);
assert_ne!(a.compute_public_output(), b.compute_public_output());
}
#[test]
fn output_bytes_matches_core_concat_output_ordering() {
let inp = inputs(
[0u8; 32],
vec![vec![0x01, 0x02], vec![0x03], vec![0x04, 0x05, 0x06]],
);
let refs: Vec<&[u8]> = inp.chunk_ciphertext.iter().map(|c| c.as_slice()).collect();
let guest_style = crate::imp::core::serving::concat_output(&refs);
assert_eq!(inp.output_bytes(), guest_style);
}
}