#include <wtk/bolt/Backend.h>
BOLT Backend API
template<typename Wire_T, typename Number_T> class BackendNumber_T const primebool const isBooleanBackend(Number_T const p, bool const ib)virtual void addGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0virtual void mulGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0virtual void addcGate(Wire_T* const out, Wire_T const* const left, Number_T const right) = 0virtual void mulcGate(Wire_T* const out, Wire_T const* const left, Number_T const right) = 0virtual void xorGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0virtual void andGate(Wire_T* const out, Wire_T const* const left, Wire_T const* const right) = 0virtual void notGate(Wire_T* const out, Wire_T const* const left) = 0virtual void copy(Wire_T* const out, Wire_T const* const left) = 0virtual void assign(Wire_T* const out, Number_T const left) = 0virtual void instance(Wire_T* const out, Number_T const left) = 0virtual void witness(Wire_T* const out, Number_T const left) = 0virtual void assertZero(Wire_T const* const wire) = 0virtual void caseSelect(Wire_T* const selected_bit, Number_T const case_number, Wire_T const* const select_wire) = 0virtual 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() = 0virtual 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_placecolumn. 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);