#include <wtk/bolt/Backend.h>
BOLT Backend API
template<typename Wire_T, typename Number_T> class Backend
Number_T const prime
bool const isBoolean
Backend(Number_T const p, bool const ib)
virtual void addGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
virtual void mulGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
virtual void addcGate(Wire_T* const out, Wire_T const* const left, Number_T const right) = 0
virtual void mulcGate(Wire_T* const out, Wire_T const* const left, Number_T const right) = 0
virtual void xorGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
virtual void andGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
virtual void notGate(Wire_T* const out, Wire_T const* const left) = 0
virtual void copy(Wire_T* const out, Wire_T const* const left) = 0
virtual void assign(Wire_T* const out, Number_T const left) = 0
virtual void instance(Wire_T* const out, Number_T const left) = 0
virtual void witness(Wire_T* const out, Number_T const left) = 0
virtual void assertZero(Wire_T const* const wire) = 0
virtual void caseSelect(Wire_T* const selected_bit, Number_T const case_number, Wire_T const* const select_wire) = 0
virtual void multiplexHelper(Wire_T* const out, std::vector<LocalWireRange<Wire_T, Number_T*>* const dummies, std::vector<Wire_T> const* const selector_bits, wtk::index_t const dummy_place)
virtual bool check() = 0
virtual void finish()
Include this API as
Members of this API live in the following namespace
namespace wtk { namespace bolt { ...
The BOLT API is parameterized on two templates.
Number_T
-
This template is the same integer-like template which the Parser API uses for numeric literals.
Wire_T
-
This template is an opaque structure supplied by the Backend for encapsulating data related to a wire. The Builder requires it to be default constructible/destructible, and the Evaluator requires it be mutable/overwritable.
template<typename Wire_T, typename Number_T> class Backend
An abstract class defining directives passed on to the ZK Backend. A backend can implement this interface for BOLT to use during evaluation. Each funciton is a handler for a different simple gate.
Wires are reported as Wire_T
pointers, which are generally constructed ahead of time and reused, rather than allocated once.
BOLT does ensure that output pointer != input pointer, but multiple input pointers could be equal.
All handlers return void
, and errors must be cached until the end of the relation when check()
is called by the user.
Number_T const prime
This public attribute must be set by the constructor to the characteristic/prime modulus.
Number_T const prime;
bool const isBoolean
This public attribute must be set by the constructor to true
if the GateSet is Boolean.
Number_T const prime;
Backend(Number_T const p, bool const ib)
The wtk::Backend<Wire_T, Number_T>
has only one constructor, with two parameters.
The first parameter, p
, is the prime modulus or characteristic.
The second parameter, ib
, is a flag indicating true
when theGateSet is Boolean and false
when Arithmetic.
Backend(Number_T const p, bool const ib) : prime(p), isBoolean(ib) { }
virtual void addGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
The backend must handle an addition.
out
may be assumed to point to a different object from left
or right
.
This method is guaranteed only to be called if this→isBoolean == false
.
virtual void addGate(Wire_T* const out,
Wire_T const* const left, Wire_T const* const right) = 0;
virtual void mulGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
The backend must handle a multiplication.
out
may be assumed to point to a different object from left
or right
.
This method is guaranteed only to be called if this→isBoolean == false
.
virtual void mulGate(Wire_T* const out,
Wire_T const* const left, Wire_T const* const right) = 0;
virtual void addcGate(Wire_T* const out, Wire_T const* const left, Number_T const right) = 0
The backend must handle an addition with a constant.
out
may be assumed to point to a different object from left
.
This method is guaranteed only to be called if this→isBoolean == false
.
virtual void addcGate(Wire_T* const out,
Wire_T const* const left, Number_T const right) = 0;
virtual void mulcGate(Wire_T* const out, Wire_T const* const left, Number_T const right) = 0
The backend must handle a multiplication with a constant.
out
may be assumed to point to a different object from left
.
This method is guaranteed only to be called if this→isBoolean == false
.
virtual void addcGate(Wire_T* const out,
Wire_T const* const left, Number_T const right) = 0;
virtual void xorGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
The backend must handle an XOR.
out
may be assumed to point to a different object from left
or right
.
This method is guaranteed only to be called if this→isBoolean == true
.
virtual void xorGate(Wire_T* const out,
Wire_T const* const left, Wire_T const* const right) = 0;
virtual void andGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0
The backend must handle an AND.
out
may be assumed to point to a different object from left
or right
.
This method is guaranteed only to be called if this→isBoolean == true
.
virtual void andGate(Wire_T* const out,
Wire_T const* const left, Wire_T const* const right) = 0;
virtual void notGate(Wire_T* const out, Wire_T const* const left) = 0
The backend must handle an AND.
out
may be assumed to point to a different object from left
.
This method is guaranteed only to be called if this→isBoolean == true
.
virtual void notGate(Wire_T* const out, Wire_T const* const left) = 0;
virtual void copy(Wire_T* const out, Wire_T const* const left) = 0
The backend must copy from left
to right
.
out
may be assumed to point to a different object from left
.
virtual void copy(Wire_T* const out, Wire_T const* const left) = 0;
virtual void assign(Wire_T* const out, Number_T const left) = 0
The backend must assign out
the constant value left
.
virtual void assign(Wire_T* const out, Number_T const left) = 0;
virtual void instance(Wire_T* const out, Number_T const left) = 0
The backend must assign out
the instance value left
.
virtual void instance(Wire_T* const out, Number_T const left) = 0;
virtual void witness(Wire_T* const out, Number_T const left) = 0
The backend must assign out
the witness value left
.
virtual void witness(Wire_T* const out, Number_T const left) = 0;
virtual void assertZero(Wire_T const* const wire) = 0
The backend must check that wire
is equal to 0
, and if this is not the case, a failure must be cached until this→check()
is called.
virtual void assertZero(Wire_T const* const wire) = 0;
virtual void caseSelect(Wire_T* const selected_bit, Number_T const case_number, Wire_T const* const select_wire) = 0
This function decides if a case is selected or active by comparison of the select_wire
to the case_number
.
If they are equal then selected_bit
must be set to 1
, otherwise it must be set to 0
.
The default implementation uses exponentiation and Fermat’s Little Theorem to make the computation.
virtual void caseSelect(Wire_T* const selected_bit,
Number_T const case_number, Wire_T const* const select_wire);
virtual void multiplexHelper(Wire_T* const out, std::vector<LocalWireRange<Wire_T, Number_T*>* const dummies, std::vector<Wire_T> const* const selector_bits, wtk::index_t const dummy_place)
Implements a multiplexer by summing a column of dummy wires conditionally on each selector bit.
This is repeated for each column of dummies.
This method is guaranteed only to be called if this→isBoolean == false
.
out
-
output wire (sum)
dummies
-
A rectangular matrix, although this method must access only the
dummy_place
column. selector_bits
-
vector of condition bits, guaranteed to have the same length as the column.
dummy_place
-
the column to be summed
Unfortunately, this method must expose the wtk::bolt::LocalWireRange<Wire_T, Number_T>
internal structure.
The backend may call only the deref(…)
method (shown here) with dummy_place
as the argument.
Wire_T* deref(wtk::index_t const idx);
Here is a pseudo-ish code this function should implement:
*out
:= sum(i
, (*dummies)[i].deref(dummy_place)
* (*selector_bits)[i]
);
virtual void multiplexHelper(Wire_T* const out,
std::vector<LocalWireRange<Wire_T, Number_T>*>* const dummies,
std::vector<Wire_T> const* const selector_bits,
wtk::index_t const dummy_place);