Skip to main content

aztec_core/abi/
buffer.rs

1use crate::types::Fr;
2use crate::Error;
3
4/// Split a byte buffer into field elements for on-chain storage.
5///
6/// The first field stores the buffer length. Subsequent fields each hold
7/// up to 31 bytes, left-aligned at byte 1 in a 32-byte field (byte 0 is zero).
8/// The output is zero-padded to `target_length`.
9pub fn buffer_as_fields(input: &[u8], target_length: usize) -> Result<Vec<Fr>, Error> {
10    let mut encoded = vec![Fr::from(input.len() as u64)];
11    for chunk in input.chunks(31) {
12        let mut padded = [0u8; 32];
13        padded[1..1 + chunk.len()].copy_from_slice(chunk);
14        encoded.push(Fr::from(padded));
15    }
16    if encoded.len() > target_length {
17        return Err(Error::Abi(format!(
18            "buffer exceeds maximum field count: got {} but max is {}",
19            encoded.len(),
20            target_length
21        )));
22    }
23    encoded.resize(target_length, Fr::zero());
24    Ok(encoded)
25}
26
27/// Reconstruct a byte buffer from field elements produced by `buffer_as_fields`.
28///
29/// The first field is the original buffer length. Subsequent fields each
30/// contribute 31 bytes (from bytes [1..32] of the big-endian representation).
31pub fn buffer_from_fields(fields: &[Fr]) -> Result<Vec<u8>, Error> {
32    if fields.is_empty() {
33        return Err(Error::Abi("empty field array".to_owned()));
34    }
35    let length = fields[0].to_usize();
36    let mut result = Vec::with_capacity(length);
37    for field in &fields[1..] {
38        let bytes = field.to_be_bytes();
39        result.extend_from_slice(&bytes[1..]);
40    }
41    result.truncate(length);
42    Ok(result)
43}