pub struct ByteVec {
pub len_bytes: Wire,
pub data: Vec<Wire>,
pub len_range: RangeInclusive<usize>,
}Expand description
A variable-length byte vector with fixed capacity determined at circuit construction time.
This struct represents a byte vector whose actual length can vary at runtime (stored in
len_bytes), but whose maximum capacity is fixed and determined by the number of data wires
allocated.
§Capacity Model
- Each wire in the
datavector holds up to 8 bytes packed in little-endian format - The capacity in bytes =
data.len() * 8 - The actual length is stored in the
len_byteswire and can be any value from 0 to the capacity
§Compile-time length range
Callers very often know a tighter compile-time bound on len_bytes than [0, capacity] (a
constant-length field, a concat output bounded by the sum of its inputs, …). len_range
records that bound so gadgets like concat can elide the dynamic
machinery that would otherwise handle the full [0, capacity] range. Invariants:
len_range.end() <= capacity(in bytes), and- the runtime
len_bytessatisfieslen_range.start() <= len_bytes <= len_range.end()(the bound is inclusive on both ends — the upper end mirrors the capacity, whichlen_bytesis allowed to reach).
This range is only sound to rely on when the wire is genuinely constrained to it: the
constructors here either fix len_bytes to a compile-time constant (new_const_len,
truncate, slice_const_range) or default to the full 0..capacity range (new,
new_inout, new_witness). new_with_len_range trusts the
caller to have enforced the range by other means (e.g. concat, where the output length is the
sum of already-constrained input lengths).
§Example
// Create a ByteVec with capacity for 32 bytes (4 wires)
let byte_vec = ByteVec::new_witness(builder, 32);
// byte_vec.data.len() == 4 (since 32 / 8 = 4)
// Can hold any actual length from 0 to 32 bytes at runtimeFields§
§len_bytes: WireThe actual length of valid data in bytes (runtime value, can be 0 to capacity).
data: Vec<Wire>The data wires, each holding up to 8 bytes. The number of wires determines the capacity: capacity = data.len() * 8.
len_range: RangeInclusive<usize>Compile-time bound on len_bytes: len_range.start() <= len_bytes <= len_range.end(). See
the struct docs for the invariants and how the range is established.
Implementations§
Source§impl ByteVec
impl ByteVec
Sourcepub fn new(data: Vec<Wire>, len_bytes: Wire) -> Self
pub fn new(data: Vec<Wire>, len_bytes: Wire) -> Self
Creates a new fixed byte vector using the given wires and wire containing the length of the data in bytes.
The length range defaults to the full 0..capacity, preserving the fully-dynamic behavior.
Sourcepub fn new_with_len_range(
data: Vec<Wire>,
len_bytes: Wire,
len_range: RangeInclusive<usize>,
) -> Self
pub fn new_with_len_range( data: Vec<Wire>, len_bytes: Wire, len_range: RangeInclusive<usize>, ) -> Self
Creates a new fixed byte vector with an explicit compile-time len_range.
The caller is responsible for ensuring len_bytes is actually constrained to lie within
len_range; this constructor only records the bound (and checks it against the capacity).
§Panics
- If
len_range.start() > len_range.end() - If
len_range.end()exceeds the capacity (data.len() * 8)
Sourcepub fn new_const_len(b: &CircuitBuilder, data: Vec<Wire>, len: usize) -> Self
pub fn new_const_len(b: &CircuitBuilder, data: Vec<Wire>, len: usize) -> Self
Creates a constant-length byte vector: len_bytes is fixed to the compile-time constant
len, so len_range = len..=len.
§Panics
- If
lenexceeds the capacity (data.len() * 8)
Sourcepub fn new_inout(b: &CircuitBuilder, max_len: usize) -> Self
pub fn new_inout(b: &CircuitBuilder, max_len: usize) -> Self
Creates a new fixed byte vector with the given maximum length as inout wires.
Sourcepub fn new_witness(b: &CircuitBuilder, max_len: usize) -> Self
pub fn new_witness(b: &CircuitBuilder, max_len: usize) -> Self
Creates a new fixed byte vector with the given maximum length as witness wires.
Sourcepub fn populate_len_bytes(&self, w: &mut WitnessFiller<'_>, len_bytes: usize)
pub fn populate_len_bytes(&self, w: &mut WitnessFiller<'_>, len_bytes: usize)
Populate the length wire with the actual vector size in bytes.
§Panics
- If
len_byteslies outsideself.len_range.
Sourcepub fn populate_bytes_le(&self, w: &mut WitnessFiller<'_>, bytes: &[u8])
pub fn populate_bytes_le(&self, w: &mut WitnessFiller<'_>, bytes: &[u8])
Sourcepub fn populate_data(&self, w: &mut WitnessFiller<'_>, data_bytes: &[u8])
pub fn populate_data(&self, w: &mut WitnessFiller<'_>, data_bytes: &[u8])
Populate the vector’s data from a byte slice.
Packs the bytes into 64-bit words in little-endian order and ensures any unused words are zeroed out.
§Panics
Panics if data_bytes.len() > self.max_len_bytes()
Sourcepub const fn max_len_bytes(&self) -> usize
pub const fn max_len_bytes(&self) -> usize
Returns the maximum length of this vector in bytes.
Sourcepub fn truncate(&self, b: &CircuitBuilder, num_wires: usize) -> ByteVec
pub fn truncate(&self, b: &CircuitBuilder, num_wires: usize) -> ByteVec
Sourcepub fn slice_const_range(
&self,
b: &CircuitBuilder,
range: Range<usize>,
) -> ByteVec
pub fn slice_const_range( &self, b: &CircuitBuilder, range: Range<usize>, ) -> ByteVec
Extracts a slice at a compile-time constant range.
This operation is significantly more efficient than the dynamic Slice circuit
because the range is known at circuit construction time, allowing for:
- Direct computation of which words are needed (no multiplexers)
- Compile-time shift amounts (no dynamic shift selection)
- Reduced constraint count
§Arguments
b- Circuit builderrange- Compile-time constant byte range to extract
§Returns
A new ByteVec containing the extracted slice with capacity rounded up to
the next word boundary (8 bytes).
§Constraints
- Validates at runtime that
range.end <= self.len_bytes - If the range is not aligned to 8-byte boundaries, words are shifted appropriately
- Bytes of the final word beyond the slice length are unconstrained (a
ByteVecmakes no guarantee about byte values past its length).
§Panics
- If
range.start > range.end - If
range.end > self.len_range.end()
§Example
// Extract bytes 3-11 from a ByteVec
let slice = byte_vec.slice_const_range(&builder, 3..11);
// slice will have capacity of 16 bytes (2 words) but length of 8 bytesTrait Implementations§
Auto Trait Implementations§
impl Freeze for ByteVec
impl RefUnwindSafe for ByteVec
impl Send for ByteVec
impl Sync for ByteVec
impl Unpin for ByteVec
impl UnsafeUnpin for ByteVec
impl UnwindSafe for ByteVec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more