Skip to main content

ByteVec

Struct ByteVec 

Source
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 data vector 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_bytes wire 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_bytes satisfies len_range.start() <= len_bytes <= len_range.end() (the bound is inclusive on both ends — the upper end mirrors the capacity, which len_bytes is 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 runtime

Fields§

§len_bytes: Wire

The 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

Source

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.

Source

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)
Source

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 len exceeds the capacity (data.len() * 8)
Source

pub fn new_inout(b: &CircuitBuilder, max_len: usize) -> Self

Creates a new fixed byte vector with the given maximum length as inout wires.

Source

pub fn new_witness(b: &CircuitBuilder, max_len: usize) -> Self

Creates a new fixed byte vector with the given maximum length as witness wires.

Source

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_bytes lies outside self.len_range.
Source

pub fn populate_bytes_le(&self, w: &mut WitnessFiller<'_>, bytes: &[u8])

Populate the ByteVec with bytes.

This method packs bytes into 64-bit words using little-endian ordering,

§Panics
  • If bytes.len() exceeds self.max_len
Source

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()

Source

pub const fn max_len_bytes(&self) -> usize

Returns the maximum length of this vector in bytes.

Source

pub fn truncate(&self, b: &CircuitBuilder, num_wires: usize) -> ByteVec

Construct a new ByteVec by truncating to num_wires.

§Panics
  • If num_wires exceeds self.data.len()
Source

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 builder
  • range - 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 ByteVec makes 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 bytes

Trait Implementations§

Source§

impl Clone for ByteVec

Source§

fn clone(&self) -> ByteVec

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more