Documentation
¶
Overview ¶
Package uints implements optimised byte and long integer operations.
Usually arithmetic in a circuit is performed in the native field, which is of prime order. However, for compatibility with native operations we rely on operating on smaller primitive types as 8-bit, 32-bit and 64-bit integer. Naively, these operations have to be implemented bitwise as there are no closed equations for boolean operations (XOR, AND, OR).
However, the bitwise approach is very inefficient and leads to several constraints per bit. Accumulating over a long integer, it leads to very inefficients circuits.
This package performs boolean operations using lookup tables on bytes. So, long integers are split into 4 or 8 bytes and we perform the operations bytewise. In the lookup tables, we store results for all possible 2^8×2^8 inputs. With this approach, every bytewise operation costs as single lookup, which depending on the backend is relatively cheap (one to three constraints).
NB! The package is still work in progress. The interfaces and implementation details most certainly changes over time. We cannot ensure the soundness of the operations.
Index ¶
- func GetHints() []solver.Hint
- type BinaryField
- func (bf *BinaryField[T]) Add(a ...T) T
- func (bf *BinaryField[T]) And(a ...T) T
- func (bf *BinaryField[T]) AssertEq(a, b T)
- func (bf *BinaryField[T]) ByteAssertEq(a, b U8)
- func (bf *BinaryField[T]) ByteValueOf(a frontend.Variable) U8
- func (bf *BinaryField[T]) Lrot(a T, c int) T
- func (bf *BinaryField[T]) Not(a T) T
- func (bf *BinaryField[T]) Or(a ...T) T
- func (bf *BinaryField[T]) PackLSB(a ...U8) T
- func (bf *BinaryField[T]) PackMSB(a ...U8) T
- func (bf *BinaryField[T]) Rshift(a T, c int) T
- func (bf *BinaryField[T]) ToValue(a T) frontend.Variable
- func (bf *BinaryField[T]) UnpackLSB(a T) []U8
- func (bf *BinaryField[T]) UnpackMSB(a T) []U8
- func (bf *BinaryField[T]) ValueOf(a frontend.Variable) T
- func (bf *BinaryField[T]) Xor(a ...T) T
- type Bytes
- func (bf *Bytes) And(a ...U8) U8
- func (bf *Bytes) AssertIsEqual(a, b U8)
- func (bf *Bytes) Not(a U8) U8
- func (bf *Bytes) Or(a ...U8) U8
- func (bf *Bytes) Select(selector frontend.Variable, a, b U8) U8
- func (bf *Bytes) Value(a U8) frontend.Variable
- func (bf *Bytes) ValueOf(a frontend.Variable) U8
- func (bf *Bytes) ValueUnchecked(a U8) frontend.Variable
- func (bf *Bytes) Xor(a ...U8) U8
- type Long
- type U8
- type U32
- type U64
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type BinaryField ¶
func New ¶
func New[T Long](api frontend.API) (*BinaryField[T], error)
New is an alias to NewBinaryField. It is retained for backwards compatibility. New uses should use NewBinaryField instead.
func NewBinaryField ¶ added in v0.14.0
func NewBinaryField[T Long](api frontend.API) (*BinaryField[T], error)
NewBinaryField creates a new BinaryField for the given integer type T specified by parameter Long. It allows to manipulate long integers in circuit.
func (*BinaryField[T]) Add ¶
func (bf *BinaryField[T]) Add(a ...T) T
Add performs addition of all inputs a modulo T. It returns the result of adding all inputs together. The number of inputs must be at least one.
For example if T is U32, then addition is performed modulo 2^32. This means that the carry bit is omitted.
func (*BinaryField[T]) And ¶
func (bf *BinaryField[T]) And(a ...T) T
And performs bitwise AND operation on all inputs a. It returns the result of ANDing all inputs together. The number of inputs must be at least one.
func (*BinaryField[T]) AssertEq ¶
func (bf *BinaryField[T]) AssertEq(a, b T)
AssertEq asserts that two long integers are equal.
func (*BinaryField[T]) ByteAssertEq ¶
func (bf *BinaryField[T]) ByteAssertEq(a, b U8)
ByteAssertEq asserts that two bytes are equal.
func (*BinaryField[T]) ByteValueOf ¶
func (bf *BinaryField[T]) ByteValueOf(a frontend.Variable) U8
ByteValueOf converts a frontend.Variable into a single byte. If the input doesn't fit into a byte then solver fails.
func (*BinaryField[T]) Lrot ¶
func (bf *BinaryField[T]) Lrot(a T, c int) T
Lrot performs left rotation of a by c bits. For example, if T is U32, then Lrot(0x12345678, 8) = 0x34567812
func (*BinaryField[T]) Not ¶
func (bf *BinaryField[T]) Not(a T) T
Not performs bitwise NOT operation on input a.
func (*BinaryField[T]) Or ¶ added in v0.12.0
func (bf *BinaryField[T]) Or(a ...T) T
Or performs bitwise OR operation on all inputs a. It returns the result of ORing all inputs together. The number of inputs must be at least one.
func (*BinaryField[T]) PackLSB ¶
func (bf *BinaryField[T]) PackLSB(a ...U8) T
PackLSB packs bytes into a long integer T assuming least significant byte first order. For example, PackLSB(0x12, 0x34, 0x56, 0x78) = 0x78563412 The number of bytes provided must match the size of T.
func (*BinaryField[T]) PackMSB ¶
func (bf *BinaryField[T]) PackMSB(a ...U8) T
PackMSB packs bytes into a long integer T assuming most significant byte first order. For example, PackMSB(0x12, 0x34, 0x56, 0x78) = 0x12345678 The number of bytes provided must match the size of T.
func (*BinaryField[T]) Rshift ¶
func (bf *BinaryField[T]) Rshift(a T, c int) T
Rshift performs right shift of a by c bits. For example, if T is U32, then Rshift(0x12345678, 8) = 0x00123456
func (*BinaryField[T]) ToValue ¶
func (bf *BinaryField[T]) ToValue(a T) frontend.Variable
ToValue converts a long integer value into a single frontend.Variable.
func (*BinaryField[T]) UnpackLSB ¶
func (bf *BinaryField[T]) UnpackLSB(a T) []U8
UnpackLSB unpacks a long integer T into bytes assuming least significant byte first order. For example, UnpackLSB(0x78563412) = (0x12, 0x34, 0x56, 0x78) The number of bytes returned matches the size of T.
func (*BinaryField[T]) UnpackMSB ¶
func (bf *BinaryField[T]) UnpackMSB(a T) []U8
UnpackMSB unpacks a long integer T into bytes assuming most significant byte first order. For example, UnpackMSB(0x12345678) = (0x12, 0x34, 0x56, 0x78) The number of bytes returned matches the size of T.
func (*BinaryField[T]) ValueOf ¶
func (bf *BinaryField[T]) ValueOf(a frontend.Variable) T
ValueOf converts a frontend.Variable into a long integer. If the input doesn't fit into T then solver fails.
func (*BinaryField[T]) Xor ¶
func (bf *BinaryField[T]) Xor(a ...T) T
Xor performs bitwise XOR operation on all inputs a. It returns the result of XORing all inputs together. The number of inputs must be at least one.
type Bytes ¶ added in v0.14.0
type Bytes struct {
// contains filtered or unexported fields
}
Bytes implements methods for manipulating bytes in circuit. Use NewBytes to create a new instance.
func NewBytes ¶ added in v0.14.0
NewBytes creates a new Bytes instance which can manipulate bytes and byte arrays. For manipulating long integers, use BinaryField instead.
This is a caching constructor, meaning that it will return the same instance if called multiple times. This is useful as internally it uses lookup tables for bitwise operations and it amortizes the cost of creating these lookup tables.
func (*Bytes) AssertIsEqual ¶ added in v0.14.0
func (*Bytes) Select ¶ added in v0.14.0
Select returns a new U8 value which is:
- if selector is true then a
- if selector is false then b
func (*Bytes) Value ¶ added in v0.14.0
Value returns the value of the U8 variables, ensuring that it is range checked. It is preferrable to use this method instead of directly using the U8.Val field.
func (*Bytes) ValueOf ¶ added in v0.14.0
ValueOf returns a constrainted U8 variable. For a constant value, use NewU8 instead.
func (*Bytes) ValueUnchecked ¶ added in v0.14.0
ValueUnchecked returns the value of the U8 variables without range checking.
type U8 ¶
type U8 struct {
// Val is the value of the byte. It can be a constant or a variable.
// NB! dont't access it directly!
Val frontend.Variable
// contains filtered or unexported fields
}
U8 represents a single byte (uint8) in the circuit. Users should not create U8 values directly, but rather use NewU8 (for in-circuit constant initialization or witness assignment) or Bytes.ValueOf (for in-circuit variable initialization).
Users should not access the U8.Val field directly, but rather use Bytes.Value method to ensure that the value is range checked to be 8 bits.
func NewU8 ¶
NewU8 creates a new U8 value. It represents a single byte. It can both be used in-circuit to initialize a constant or as a witness assignment. For in-circuit initialization use Bytes.ValueOf method instead which ensures that the value is range checked.
func NewU8Array ¶
NewU8Array is a utility method to create a slice of U8 from a slice of uint8.
type U32 ¶
type U32 [4]U8
func NewU32 ¶
NewU32 creates a new U32 value. It represents a 32-bit unsigned integer which is split into 4 bytes. It can both be used in-circuit to initialize a constant or as a witness assignment. For in-circuit initialization use BinaryField.ValueOf method instead which ensures that the value is range checked.
func NewU32Array ¶
NewU32Array is a utility method to create a slice of U32 from a slice of uint32.
type U64 ¶
type U64 [8]U8
func NewU64 ¶
NewU64 creates a new U64 value. It represents a 64-bit unsigned integer which is split into 4 bytes. It can both be used in-circuit to initialize a constant or as a witness assignment. For in-circuit initialization use BinaryField.ValueOf method instead which ensures that the value is range checked.
func NewU64Array ¶
NewU64Array is a utility method to create a slice of U64 from a slice of uint64.