barretenberg
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | List of all members
proof_system::plonk::stdlib::byte_array< Builder > Class Template Reference

Public Types

typedef std::vector< field_t< Builder > > bytes_t
 

Public Member Functions

 byte_array (Builder *parent_context=nullptr)
 
 byte_array (Builder *parent_context, size_t const n)
 
 byte_array (Builder *parent_context, std::string const &input)
 
 byte_array (Builder *parent_context, std::vector< uint8_t > const &input)
 Create a byte array out of a vector of uint8_t bytes.
 
 byte_array (Builder *parent_context, bytes_t const &input)
 
 byte_array (Builder *parent_context, bytes_t &&input)
 
 byte_array (const field_t< Builder > &input, const size_t num_bytes=32)
 Create a byte_array out of a field element.
 
 byte_array (const safe_uint_t< Builder > &input, const size_t num_bytes=32)
 
template<typename ItBegin , typename ItEnd >
 byte_array (Builder *parent_context, ItBegin const &begin, ItEnd const &end)
 
 byte_array (const byte_array &other)
 
 byte_array (byte_array &&other)
 
byte_arrayoperator= (const byte_array &other)
 
byte_arrayoperator= (byte_array &&other)
 
 operator field_t< Builder > () const
 Convert a byte array into a field element.
 
field_t< Builderoperator[] (const size_t index) const
 
byte_arraywrite (byte_array const &other)
 
byte_arraywrite_at (byte_array const &other, size_t index)
 
byte_array slice (size_t offset) const
 
byte_array slice (size_t offset, size_t length) const
 Slice length bytes from the byte array, starting at offset. Does not add any constraints.
 
byte_array reverse () const
 Reverse the bytes in the byte array.
 
size_t size () const
 
bytes_t const & bytes () const
 
bool_t< Builderget_bit (size_t index) const
 Extract a bit from the byte array.
 
void set_bit (size_t index, bool_t< Builder > const &value)
 Set a bit in the byte array.
 
void set_byte (size_t index, const field_t< Builder > &byte_val)
 
void set_context (Builder *ctx)
 
Builderget_context () const
 
std::vector< uint8_t > get_value () const
 
std::string get_string () const
 

Constructor & Destructor Documentation

◆ byte_array() [1/2]

template<typename Builder >
proof_system::plonk::stdlib::byte_array< Builder >::byte_array ( Builder parent_context,
std::vector< uint8_t > const &  input 
)

Create a byte array out of a vector of uint8_t bytes.

Warning
This constructor will instantiate each byte as a circuit witness, NOT a circuit constant. Do not use this method if the input needs to be hardcoded for a specific circuit

◆ byte_array() [2/2]

template<typename Builder >
proof_system::plonk::stdlib::byte_array< Builder >::byte_array ( const field_t< Builder > &  input,
const size_t  num_bytes = 32 
)

Create a byte_array out of a field element.

The length of the byte array will default to 32 bytes, but shorter lengths can be specified. If a shorter length is used, the circuit will NOT truncate the input to fit the reduced length. Instead, the circuit adds constraints that VALIDATE the input is smaller than the specified length

e.g. if this constructor is used on a 16-bit input witness, where num_bytes is 1, the resulting proof will fail.

Description of circuit

Our field element is input. Say the byte vector provided by the prover consists of bits b0,...,b255. These bits are used to construct the corresponding uint256_t validator := \sum_{i=0}^{8num_bytes-1} 2^{i}b_{i}, and validator is copy constrained to be equal to input. However, more constraints are needed in general.

Let r = barretenberg::fr::modulus. For later applications, we want to ensure that the prover must pass the bit decomposition of the standard representative of the mod r residue class containing input, which is to say that we want to show validator lies in [0, ..., r-1]. By the formula for validator, we do not have to worry about it wrapping the modulus if num_bytes < 32 or, in the default case, if the input fits into 31 bytes.

Suppose now that num_bytes is 32. We would like to show that r - validator lies > 0 as integers, but this cannot be done inside of uint256_t since validator can be any uint256_t, hence its negative is not constrained to lie in any proper subset. We therefore split it and r-1 into two smaller limbs and make comparisons using range constraints in uint256_t (shifting r to turn a > into a >=).

By the construction of validator, it is easy to extract its top 16 bytes shifted_high_limb = 2^{128}v_hi, so that one gets a decomposition by computing v_lo := validator - 2^{128}v_hi. We separate the problem of imposing that validator <= r - 1 into two cases.

 Case 0: When s_lo < v_lo, we must impose that v_hi < s_hi, i.e., s_hi - v_hi - 1 >= 0.
 Case 1:           >=                               =<            s_hi - v_hi     >= 0.

To unify these cases, we need a predicate that distinguishes them, and we need to use this to effect a shift of 1 or 0 in v_hi, as the case may be. We build this now. Consider the expression s_lo - v_lo. As an integer, this lies in [-2^128+1, 2^128-1], with Case 0 corresponding to the numbers < 0. Shifting to y_lo := s_lo - v_lo + 2^128, Case 0 corresponds to the range [1, 2^128-1]. We see that the 129th bit of y_lo exactly indicates the case. Extracting this (and the 130th bit, which is always 0, for convenience) and adding it to v_hi, we have a uniform constraint to apply. Namely, setting y_overlap := 1 - (top quad of y_lo regarded as a 130-bit integer) and y_hi := s_hi - v_hi - y_overlap, range constrianing y_hi to 128 bits imposes validator < r.

Member Function Documentation

◆ get_bit()

template<typename Builder >
bool_t< Builder > proof_system::plonk::stdlib::byte_array< Builder >::get_bit ( size_t  index_reversed) const

Extract a bit from the byte array.

get_bit treats the array as a little-endian integer e.g. get_bit(1) corresponds to the second bit in the last, 'least significant' byte in the array.

◆ operator field_t< Builder >()

template<typename Builder >
proof_system::plonk::stdlib::byte_array< Builder >::operator field_t< Builder >
explicit

Convert a byte array into a field element.

The byte array is represented as a big integer, that is then converted into a field element. The transformation is only injective if the byte array is < 32 bytes. Larger byte arrays can still be cast to a single field element, but the value will wrap around the circuit modulus

◆ set_bit()

template<typename Builder >
void proof_system::plonk::stdlib::byte_array< Builder >::set_bit ( size_t  index_reversed,
bool_t< Builder > const &  new_bit 
)

Set a bit in the byte array.

set_bit treats the array as a little-endian integer e.g. set_bit(0) will set the first bit in the last, 'least significant' byte in the array

For example, if we have a 64-byte array filled with zeroes, set_bit(0, true) will set values[63] to 1, and set_bit(511, true) will set values[0] to 128

Previously we did not reverse the bit index, but we have modified the behavior to be consistent with get_bit

The rationale behind reversing the bit index is so that we can more naturally contain integers inside byte arrays and perform bit manipulation

◆ slice()

template<typename Builder >
byte_array< Builder > proof_system::plonk::stdlib::byte_array< Builder >::slice ( size_t  offset,
size_t  length 
) const

Slice length bytes from the byte array, starting at offset. Does not add any constraints.

Note that the syntax here differs for the syntax used for slicing uint256_t's.


The documentation for this class was generated from the following files: