WizToolKit Manual

WizToolKit

This is a collection of tools, provided by team Wizkit, for working with the SIEVE IR. It In addition to a few command-line tools, it has an extensive C++ API for manipulating the SIEVE IR. This release of WizToolKit corresponds to version 1.0.0 of the SIEVE IR Specification.

If you’re not familiar with the SIEVE IR, have a look at our introduction to the SIEVE IR. It represents ZK relations using circuits, and the instance and short-witness as input streams.

Command-line

The following tools are available on the command-line from WizToolKit.

wtk-firealarm (checking and evaluating)

Checks an individual IR resource for well-formedness. For a triple of relation, instance, and short-witness it checks for evaluation validity.

wtk-press (format and feature conversions)

Converts between the text and binary formats of the IR. It can also replace IR @switch directives with a multiplexer implementation using @loops and a @function.

wtk-viz (visualization)

Visualize the IR by converting it to Graphviz.

wtk-bolt (example and testing)

Invokes the BOLT or PLASMASnooze interpreters without ZK. For use in testing or as an example. See WizToolKit for Backends for more information on these.

For more information on these tools see WizToolKit on the command-line.

Parsing the IR

WizToolKit enables parsing both text and binary profiles of the SIEVE IR. The parsing API is designed for maximal flexibility, parsing the header first and then allowing the user to decide how to proceed.

In addition to both IR-Formats, WizToolKit can parse a resource with either a streaming parser (when grammar is limited to IR-Simple) or a syntax-tree parser. It also allows the user to supply a numeric type for parsing field-element literals via a template parameter, and after parsing the header to possibly downgrade to uint64_t or uint32_t for the remaining IR body.

Parser Format Comment

ANTLR

Text

Uses the ANTLR generator. "Obviously" correct, parses line-numbers, slow

IRRegular

Text

Fast, minimal memory use, no line-numbers

FlatBuffer

Binary

FlatBuffer parser

For more information see Parsing the IR.

For ZK Backends

For ZK Backends, WizToolKit provides a simple Backend API, and two interpreters to drive the API.

BOLT

first builds an augmented representation of the relation while checking for well-formedness. Then it evaluates without needing any well-formedness checks or having to stop and translate indices to actual wires. This is ideal for relations which make heavy use of loops.

PLASMASnooze

(A pun on FIREALARM) simply traverses the IR syntax-tree doing on-the-fly well-formedness checks.

For more information see WizToolKit for ZK Backends.

Other APIs

The entirety of the WizToolKit command-line is available as API, however not all of it is well documented.

Building

WizToolKit uses CMake, Python3, Java (optional), and a number of other utilities during build, of course in addition to a C++ compiler. This all is orchestrated using make, and the familiar pattern should work. Build artifacts are typically deposited in the target/ directoy.

make
make install

See the Install Guide for details, and for a list of necessary dependencies.

Licensing

The source code and other substantial material in this directory is Copyright © 2020-2022 Stealth Software Technologies, Inc.

This version of WizToolKit has been approved for public release under the open-source MIT License.

Distribution Statement A: Approved for Public Release, Distribution Unlimited.

This material is based upon work supported by DARPA under Contract No. HR001120C0087. Any opinions, findings and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of DARPA.

Installing WizToolKit

Linux and Unix derivitives

We’ve compiled a list of installation instructions for a few common systems.

RedHat/CentOS-Stream/Rocky/Alma 8

These systems are regularly tested by CI. Starting from a 'minimal installation', You will need to install these dependencies with yum.

yum install \
  epel-release \
  yum-utils
yum config-manager --set-enabled powertools
yum install \
  git \
  tar \
  make \
  wget \
  unzip \
  cmake \
  libuuid \
  libuuid-devel \
  gcc-c++ \
  diffutils \
  which \
  java-11-openjdk-devel \
  java-11-openjdk-headless \
  python39 \
  openssl \
  openssl-devel

Once installed, you can invoke make as normal. Keep in mind, that make will download additional dependencies.

make
make install

RedHat/CentOS 7

These systems are tested regularly in CI, however the ANTLR parser does not build due to differences in C++ dialects. Starting with a 'minimal installation' You will need to install these dependencies with yum.

yum install epel-release
yum install \
  git \
  tar \
  make \
  wget \
  unzip \
  cmake3 \
  libuuid \
  libuuid-devel \
  gcc-c++ \
  diffutils \
  which \
  java-11-openjdk-devel \
  java-11-openjdk-headless \
  python3 \
  openssl \
  openssl-devel

To use make, you will need to disable ANTLR. Keep in mind, that make will download additional dependencies.

make ENABLE_ANTLR=0 CMAKE_CMD=cmake3
make install

Ubuntu 18.04 LTS

This platform is regularly tested in CI. To install dependencies

apt-get install \
  git \
  build-essential \
  make \
  wget \
  unzip \
  cmake \
  g++ \
  uuid-dev \
  default-jdk \
  python3 \
  libssl-dev

Build is as normal. Keep in mind, that make will download additional dependencies.

make
make install

Ubuntu 20.04 LTS

This platform is regularly tested in CI. To install dependencies

apt-get install \
  git \
  build-essential \
  make \
  wget \
  unzip \
  cmake \
  g++ \
  uuid-dev \
  default-jdk \
  python3 \
  libssl-dev

Build is as normal. Keep in mind, that make will download additional dependencies.

make
make install

Windows 10

We are not able to regularly test this platform as of yet, but we do some manual testing on occasion. We find that windows builds are best done within the MSYS2’s MinGW64 environment. After installing MSYS2, launch "MSYS2 MinGW 64-bit" from the "start-button".

To install the necessary dependencies use pacman.

pacman -S --needed \
  tar \
  git \
  wget \
  make \
  unzip \
  diffutil \
  mingw-w64-x86_64-gcc \
  mingw-w64-x86_64-make \
  mingw-w64-x86_64-cmake \
  mingw-w64-x86_64-openssl

Then you will need to invoke make with the correct variables.

  • ANTLR doesn’t compile in MSYS2 because Java doesn’t exist.

  • make should be invoked as normal, but when it invokes make it should use mingw32-make.

  • CMake should use the 'MinGW Makefiles' generator.

  • The C compiler should be `/mingw64/bin/x86_64-w64-mingw32-g.exe`

To do all this, the following make command is best. Keep in mind, that make will download additional dependencies.

make ENABLE_ANTLR=0 MAKE_CMD=mingw32-make CMAKE_GENERATOR='MinGW Makefiles' CXX=/mingw64/bin/x86_64-w64-mingw32-g++.exe
make ENABLE_ANTLR=0 MAKE_CMD=mingw32-make CMAKE_GENERATOR='MinGW Makefiles' CXX=/mingw64/bin/x86_64-w64-mingw32-g++.exe install

To use WizToolKit commandline tools beyond the realm of MSYS2, (for example from cmd.exe) you will need to add to your PATH. Then you can invoke wtk- commands by their absolute path (or add their path to the PATH as well).

PATH=%PATH%;C:\msys64\mingw64\bin;C:\msys64\mingw64\lib
C:\msys64\usr\local\bin\wtk-firealarm.exe

Generic Build Guide

Dependencies

The build system for WizToolKit depends on a number of tools. See also the WizToolKit Software Bill-of-Materials

  • GNU Make: for task orchestration

  • CMake: for C++ build orchestration

  • C++ Compiler (tested against g+` and `clang+)

  • wget: for downloading dependencies

  • Java Runtime 1.8 (or higher): for running the ANTLR tool (required only at build time)

  • Python 3: for generating portions of the IRRegular text parser (required only at build time).

  • pkg-config: is required by CMake, and apparently not always installed by default on Ubuntu.

  • OpenSSL libcrypto and sst::bignum:

    • OpenSSL should be provided by the system.

    • sst::bignum is downloaded automatically.

    • Only the WizToolKit command line tools use the unlimited precision number library openssl/bn.h and C++ wrapper sst::bignum.

    • the WizToolKit API does not link to these library.

  • ANTLR 4: for generating and running the wtk/antlr/Parser.h parser implementation.

    • downloaded automatically at build time.

    • the runtime may require the libuuid-devel package (or equivalent from your system’s package manager).

    • may be disabled with make ENABLE_ANTLR=0

  • FlatBuffers 2.0.0: to implement the binary format of the IR specification via the FlatBuffer Parser.

    • may be disabled with make ENABLE_FLATBUFFER=0

  • Stealth logging: For reporting errors and other conditions at runtime.

    • this is used by the WizToolKit API.

    • downloaded automatically at build time.

  • Google Test: for running unit tests.

    • downloaded automatically at build time.

    • Only used during testing.

Make Targets and Options

After downloading or git cloneing a WizToolKit package, to quickly install run the following commands.

 > make
 > make install # as root

The makefile has the following more specific targets,

  • deps: calls scripts to download all the non-system dependencies.

  • gen_parser: calls scripts which do code-generation for the parser implementations.

  • configure: calls CMake to configure the C++ build system. The following environment variables are respected.

    • BUILD_TYPE: indicates whether to use Debug or Release mode. Defaults to Release.

    • PREFIX: is the installation prefix to use when calling install. Defaults to /usr/local.

    • CXX: to change the compiler

    • ENABLE_ANTLR: enables compile of the ANTLR parser, otherwise only IRRegular is produced. (default 1)

    • ENABLE_FLATBUFFER: enables compile of the FlatBuffer parser (default 1).

  • build: calls CMake generate make files.

  • test: (default target) will run the unit tests.

  • install: installs all WizToolKit files to the system.

  • clean: will remove all build files.

  • deps-clean: will remove all dependencies.

WizToolKit on the Command-Line

FIREALARM (Checking and Evaluating)

FIREALARM stands for Friendly IR Evaluator And Logic Assertion and Rejection Machine, it checks and evaluates IR resources without ZK. Its intention is to be as obviously compliant with the IR Specification as possible. When given a relation, wtk-firealarm will also print gate counts before completion.

When given a single resource wtk-firealarm will checks for well-formedness. For a relation, this means that each wire is assigned before it is used, and that it is never reused ("topological ordering", and "single static assignment (SSA)"). For an instance or short witness, this simply means that each value in the stream is a field-element (e.g. does not exceed the field’s characteristic).

When given all three resources, wtk-firealarm will evaluate the relation with the instance and short witness, indicating if the proof should be valid or not (evaluation validity). It can also generate a program trace at two levels of detail.

wtk-firealarm and other WizToolKit utilities may identify resource types using the following file-suffixes. Although the IR Specification calls for all binary resources to be identified by a .sieve extension (when applicable), WizToolKit uses these suffixes instead. The IR Specification does not prescribe any file-suffixes for text resources.

*.rel

relation

*.ins

instance

*.wit

short witness

Command-Line Options/Flags

-i

Use the IRRegular text parser, instead of the ANTLR text parser.

-f

Use the FlatBuffer binary parser, instead of the ANTLR text parser. This option is required in order to check binary resources.

-t

Produces a "light" trace, showing function-boundaries, instance and witness values, and assertions. wtk-firealarm must be invoked with all three resources for this to take affect.

-T

Produces a "heavy" trace, all wire assignments, in addition to a "light" trace. wtk-firealarm must be invoked with all three resources for this to take affect.

-h or --help

Print the help text.

-v or --version

Print the version text.

Example Invocations

To check a relation, instance, or witness for well-formedness.

wtk-firealarm relation_file.rel
wtk-firealarm instance_file.ins
wtk-firealarm witness_file.wit

To check all three for evaluation validity.

wtk-firealarm relation_file.rel instance_file.ins witness_file.wit

To check with binary IR.

wtk-firealarm -f bin_relation_file.rel bin_instance_file.ins bin_witness_file.wit

PRESS (Format and Feature Conversion)

PRESS, as in printing-press, is short for Printing and Representation Exchange Software Suite. wtk-press is a tool for changing the format of the IR or to remove unwanted features from the IR. Press can convert between the text and binary formats of the IR, or it can replace @switch directives with a multiplexer. The multiplexer is composed with @for loops, and a @function(check_case, …​.), which does have to exponentiate by p-1 when using arithmetic gates.

Command-Line Modes

wtk-press uses a <mode> <input-file> [ <output-file> ] format on its command line. Available modes are as follows. Text parsing is always done with IRRegular.

b2b

Binary to binary

b2mux

Binary to binary, with multiplex converter (if necessary)

b2t

Binary to text

t2b

Text to binary

t2mux

Text to text, with multiplex converter (if necessary)

t2t

Text to text

It also has some more testing oriented modes, which convert to nothing. Essentially they are for testing and profiling the parsers.

a2n

ANTLR to nothing

b2n

Binary to nothing

t2n

Text (IRRegular) to nothing

Example invocations

To convert from a text file to a binary file, or reverse.

wtk-press t2b relation_file.rel bin_relation_file.rel
wtk-press b2t bin_relation_file.rel > relation_file_copy.rel

To remove the @switch features.

wtk-press t2mux relation_file.rel relation_file_mux.rel
wtk-press b2mux bin_relation_file.rel bin_relation_file_mux.rel

Viz (Visualization)

For assistance in visualizing the IR, we came up with an IR to Graphviz converter (called wtk-viz). wtk-viz expects its input to be a relation, and produces a dot graph as output. It traverses the IR Syntax Tree, and in most cases makes a fairly naive translation into the Dot language. In the case of for-loops, wtk-viz repeats the loop scope mappings for each iteration of the loop, as it shows a better picture of the web created by repeated mappings.

Command Line Usage

wtk-viz accepts arguments in a [ options…​ ] <input.rel> [ <output.rel> ] form. These are the available options.

--fg <color>

Changes the color of nodes, edges, and text ("foreground") to the given HTML color.

--bg <color>

Changes the color of the background to the given HTML color.

-f

Use FlatBuffers to parse the binary relation (defaults to Text/IRRegular).

-h or --help`

Print the help text.

-v or --version`

Print the version information.

Example invocations

wtk-viz is invoked first to produce dot source, followed by the dot compiler to generate an image. dot invocation may take a long time for large circuits.

wtk-viz relation_file.rel relation_graph.dot
dot -Tsvg relation_graph.dot -o relation_graph.svg

BOLT (Example and Testing)

WizToolKit delivers the wtk::bolt API for implementing ZK Backends in the IR. The wtk-bolt command-line tool serves for testing this API in a non-ZK and as an example of invoking the wtk::bolt API. More information may be found in WizToolKit for Backends.

wtk::bolt implements two intepreters, BOLT for relations with heavy use of loops and PLASMASnooze for relations which are largely IR-Simple. PLASMASnooze also implements the Parser’s streaming API for additional performance when parsing IR-Simple (rather than nearly simple). Invocation is wtk-bolt [ bolt | plasmasnooze | stream ] <relation.rel> <instance.ins> <witness.wit>.

Parsing the IR

WizToolKit has a simple unified API for parsing both forms of the IR. This page will start with number representations in the IR, then explain the options available for parsing, and finally a deeper dive into common paths for parsing.

Numbers in the IR

The SIEVE IR has two distint categories of numbers

Wire indexes

These are represented with wtk::index_t, a typedef of uint64_t.

Field element literals

These are numbers mod the relations characteristic, which may be arbitrarily large. For maximal flexibility, WizToolKit uses a Number_T template parameter, which should be integer-like (e.g. implement operators for +, *, <<, etc. Enough to implement string-to-int conversions).

Parsing Options

WizToolKit has three parser implementations, however all implement a common interface through the wtk::Parser<Number_T> abstract class (#include <wtk/Parser.h>). It is responsible for parsing the IR’s front matter, returning control for the user to decide how to parse the IR body, and then delegating the body to a helper, also with a common interface.

As an abstract class, wtk::Parser<Number_T> must be instantiated as one of its concrete implementations. WizToolKit offers three such implementations.

All have a constructor which takes a std::string naming the file to open. Some have additional constructors.

Before going any further, it is worth thinking about the context for parsing the IR. Is just a relation being parsed? Are all three of relation, instance, and short witness being parsed? When parsing all three, we have found it easiest to expect them listed in a defined order and fail if they deviate rather than attempting to reorder them on the fly. Later in this page we will show the expected order approach.

Here is the creation of an IRRegular parser with unsigned long as its Number_T (field-literal type).

std::string relation_name = /* ... */;

wtk::irregular::Parser<unsigned long> parser(relation_name);

Once the parser is created, the front matter is easy to parse. parser.parseHdrResParams() returns true on success, and sets public attributes of the parser for front matter attributes. To check that it is a relation, the parser has a resource attribute.

if(!parser.parseHdrResParams()
    || parser.resource != wtk::Resource::relation)
{
  /* handle errors */
}

Here is a summary of the front matter attributes.

  • parser.version is the IR version number. Its a triplet of major, minor, and patch.

Warning
WizToolKit makes little attempt to handle older IR releases.
Caution
The parser.gateSet and parser.featureToggles attributes are assigned only for the relation, not for the instance or short witness.

Now the user may check the front matter for acceptability. For example, that the characteristic is prime, or from a specific family of primes. The user may also want to error here if the Gate Set or a Feature Toggle is unsupported.

Next, the user must choose how to parse the body, the instance, and the short witness. The headers of the instance and short witness can be parsed similarly to the relation’s. However, the instance and short_witness do not have Gate Set or Feature Toggles, and must defer to the relation.

A critical decision is whether the Gate Set is Boolean or arithmetic. This is because the parsing API splits on these boundaries. Another potential decision is whether or not the relation is IR-Simple. WizToolKit’s parsers have a streaming API for IR-Simple, which may improve performance for some relations. However, the streaming API cannot handle non-simple relations.

std::string instance_name = /* ... */;
std::string short_witness_name = /* ... */;
wtk::irregular::Parser<unsigned long> instance_parser(instance_name);
wtk::irregular::Parser<unsigned long> short_witness_parser(short_witness_name);

if(!instance_parser.parseHdrResParams()
    || !short_witness_parser.parseHdrResParams()
    || parser.characteristic != instance_parser.characteristic
    || parser.characteristic != short_witness_parser.characteristic)
{
  /* handle error */
}

if(parser.resource == wtk::Resource::relation)
  && parser.gateSet.gateSet == wtk::GateSet::arithmetic)
{
  // Parse arithmetic relation
  wtk::AritmeticParser<unsigned long>* arith_parser = parser.arithmetic();

  if(parser.featureToggles.simple()) // select the streaming API
  {
    // See Streaming API
  }
  else
  {
    // See Syntax Tree API
  }
}
else if(parser.resource == wtk::Resource::relation)
  && parser.gateSet.gateSet == wtk::GateSet::boolean)
{
  // Parse boolean relation, Note that the template is dropped,
  // because Boolean literals are always given as uint8_t.
  wtk::BooleanParser* bool_parser = parser.arithmetic();
  /* Omitted... */
}

Parsing the Instance and Short Witness

Both the instance and short-witness are abstracted as streams in the SIEVE IR. WizToolKit handles these streams through the wtk::InputStream<Number_T> API.

The wtk::InputStream<Number_T> objects are obtained through the parser after specializing to arithmetic or boolean.

// Get an arithmetic parser for an instance
wtk::ArithmeticParser<unsigned long>* a_ins_parser = instance_parser.arithmetic();
wtk::InputStream<unsigned long>* a_ins = a_ins_parser->instance();

// Similarly, for Boolean short witness (as an example; instance and short
// witness should have the same type).
wtk::BooleanParser* b_wit_parser = short_witness_parser.arithmetic();
wtk::InputStream<uint8_t>* b_wit = b_wit_parser->shortWitness();

Once a stream is obtained, its next(…​) method may be called repeatedly for each element of the stream. The return type of next(…​) will indicate if it succeeded, failed, or reached the end of the stream. It has a return-by-pointer argument for the stream element.

unsigned long ins_val = 0;
wtk::StreamStatus status = a_ins->next(&ins_val);
if(status == wtk::StreamStatus::end) { /* End of stream */ }
else if(status == wtk::StreamStatus::error) { /* mid-stream parser error */ }

Some of the parsers (namely ANTLR and FlatBuffer) will parse the entire stream up front, in which case a parser error is indicated on the first element, regardless of its place in the stream. Other parsers (namely IRRegular) work in a more true stream-wise fashion, reporting the error as it occurs.

Streaming API for Relations

The Streaming API, IR-Simple relations are parsed one gate at a time and reported immediately. This only works for IR-Simple because these relations have no nested scopes or repetition.

To report gates, the user must implement the wtk::ArithmeticStreamHandler<Number_T> or wtk::BooleanStreamHandler abstract class (depending on Gate Set, obviously). A brief example for Arithmetic is shown here.

class UserArithmeticStreamHandler : public wtk::ArithmeticStreamHandler<unsigned long>
{
  void handleAdd(wtk::index_t const out, // output wire-number
      wtk::index_t const left_in,        // left input wire-number
      wtk::index_t const right_in)       // right input wire-number
    override
  {
    /* omitted */
  }

  void handleMul(wtk::index_t const out, // output wire-number
      wtk::index_t const left_in,        // left input wire-number
      wtk::index_t const right_in)       // right input wire-number
    override
  {
    /* omitted */
  }

  /* Remaining methods omitted... */
};
// For an arithmetic simple relation
UserArithmeticStreamHandler handler;
if(!arith_parser->parseStream(&handler)) { /* Parse Error */ }

// For a Boolean simple relation
UserBooleanStreamHandler handler;
if(!bool_parser->parseStream(&handler)) { /* Parse Error */ }

Syntax Tree API for Relations

The Syntax Tree API can handle any relation, regardless of its feature set. However, it must parse the entire relation ahead of time, and allocate a syntax tree, which for very long relations can consume a lot of memory.

The syntax tree is defined by #include <wtk/IRTree.h>. At a top-level it is defined by the wtk::IRTree<Number_T>, which aggregates function definitions and the relation’s main body. Each scope is a wtk::DirectiveList<Number_T> with the ability to retrieve gates such as wtk::BinaryGate (binary referring to its cardinality) or wtk::Input (for the instance or short-witness).

The Tree is again retrieved through the wtk::ArithmeticParser<Number_T> or wtk::BooleanParser parseTree() method (only Arithmetic shown).

wtk::IRTree<unsigned long>* ir_tree = arith_parser->parseTree();
if(ir_tree == nullptr) { /* Parser error */ }

// To be implemented by the user.
process_ir_tree(ir_tree);

To process the relation, the user must do a tree traversal. At a top level, the wtk::IRTree<Number_T> holds a list of function declarations (we’ll get to these later), and the relation’s main body. The main body is just a wtk::DirectiveList<Number_T>, which is an indirectly-recursive type, defining much of the syntax tree.

void process_ir_tree(wtk::IRTree<unsigned long>* tree)
{
  // See Syntax Tree API for Functions for function-declarations.

  // The circuit's entry point is its body.
  process_directive_list(tree->body());
}

Processing the wtk::DirectiveList<Number-T> is a simple matter of traversing each directive in the scope, and switching on its type. Here is an example.

void process_directive_list(wtk::DirectiveList<unsigned long>* dir_list)
{
  // The DirectiveList is a tree type, leaf-nodes are typically gates
  // (@and/@xor/@mul/etc.) with other nodes taking the form of higher
  // level features.

  for(size_t i = 0; i < dir_list->size(); i++)
  {
    switch(dir_list->type(i))
    {
    case wtk::DirectiveList<unsigned long>::BINARY_GATE:
    {
      // the "binary" (in signature, not value) gate describes
      // @and/@xor/@mul/@add gates.
      wtk::BinaryGate* gate = dir_list->binaryGate(i);
      // these are the input and output wire numbers of the gate
      wtk::index_t left_input_wire = gate->leftWire();
      wtk::index_t right_input_wire = gate->rightWire();
      wtk::index_t output_wire = gate->outputWire();

      // The gate's calculation is an enum
      switch(gate->calculation())
      {
      case wtk::BinaryGate::AND: { break; }
      case wtk::BinaryGate::XOR: { break; }
      case wtk::BinaryGate::ADD: { break; }
      case wtk::BinaryGate::MUL: { break; }
      }

      break;
    }
    /* other gate-types omitted for brevity */
    case wtk::DirectiveList<unsigned long>::ANON_FUNCTION:
    {
      wtk::AnonFunction<unsigned long>* anon_func = dir_list->anonFunction(i);
      // The signature of the function, along with its inputs/outputs
      // is easily retrievable.
      wtk::WireList* output_wires = anon_func->outputList();
      wtk::WireList* input_wires = anon_func->inputList();
      wtk::index_t num_instance_vals = anon_func->instanceCount();
      wtk::index_t num_witness_vals = anon_func->shortWitnessCount();

      // To process the body of the anonymous function, use recursion.
      process_directive_list(anon_func->body());
      break;
    }
    /* Other feature-types omitted for brevity */
    }
  }
}

Syntax Tree API for Functions

For IR named-functions, the body of a function and its invocation are split. All function-declarations are listed at the top of a relation. Correspondingly, the wtk::IRTree<Number_T> has a functionDeclare(i) method for retrieval, and size() indicating how many may be retrieved.

For easy access, we suggest entering the function declarations into a std::map or std::unordered_map.

// declare a map to hold them
std::map<std::string, wtk::FunctionDeclare<unsigned long>*> functions_map;

  // enter each function-declaration into the map
  for(size_t i = 0; i < tree->size(); i++)
  {
    wtk::FunctionDeclare<unsigned long>* function = tree->functionDeclare(i);

    // function->name() is a char* while std::map works only with std::strings
    // with c++17, it should be okay to use std::string_view so long as
    // *tree outlives functions_map
    std::string name(function->name());

    // check that the function wasn't previously declared
    auto finder = functions_map.find(name);
    if(finder != functions_map.end()) { /* Error */ }

    functions_map[name] = function;
  }

When a function is invoked (with a wtk::FunctionInvoke directive), its is now just a matter of looking up its name in the map.

    case wtk::DirectiveList<unsigned long>::FUNCTION_INVOKE:
    {
      wtk::FunctionInvoke* invoke = dir_list->functionInvoke(i);

      std::string name(invoke->name());
      auto finder = functions_map.find(name);
      if(finder == functions_map.end()) { /* Error */ }

      wtk::FunctionDeclare<unsigned long>* declaration = finder->second;

      // To process the body of the function, use recursion.
      process_directive_list(declaration->body());
      break;
    }

For more information about the IR Syntax Tree, See #include <wtk/IRTree.h>.

WizToolKit for Backends

WizToolKit’s BOLT and PLASMASnooze IR interpreters share a common Backend API. The advantage of this is it allows the backend to focus on proofs and reuse IR semantics from WizToolKit. BOLT is a "two-pass" interpreter and is most ideally suited for relations which rely heavily on loops. PLASMASnooze is a "single-pass" interpreter and picks up the slack when very few gates are reused.

The following includes are required.

#include <wtk/bolt/Builder.h>

the build phase of the BOLT interpreter.

#include <wtk/bolt/Evaluator.h>

the evaluate phase of BOLT interpreter.

#include <wtk/bolt/PLASMASnooze.h>

the PLASMASnooze interpreter.

#include <wtk/bolt/ArithmeticPLASMASnoozeHandler.h>, and #include <wtk/bolt/BooleanPLASMASnoozeHandler.h>

the PLASMASnooze interpreter, adapted to the Streaming Parser API.

#include <wtk/bolt/Backend.h>

the interface which a backend implementor must implement.

For those who are curious about the naming scheme of these, BOLT is short for Better Optimization via Lookup-reuse and Two-pass. PLASMASnooze is an improvement over FIREALARM in the sense of performance and of plugability with ZK Backends. However, it is also a disprovement in the sense that it relaxes certain IR semantics, for example, it allows reassignment to a wire, after the wire was @deleted. Thus PLASMA is an improvement upon FIRE, and Snooze is the opposite of ALARM. PLASMASnooze stands for Practical Local Acceleration for Single-pass with Malleable Assumtions Snooze.

Numeric Representations

In this API there are generally three numeric representation types.

Wire numbers

A typedef named wtk::index_t defines the 64-bit unsigned integers (with wraparound) required by the IR specification for indices in the wire numbering system. These are almost entirely hidden from the backend.

Wire values

A template parameter which is typically referred to as Wire_T must be specified by the backend to carry the value across each wire.

Parser literals

A template parameter which is typically referred to as Number_T must be the same numeric type as parameterizing the parser.

The Backend API

The wtk::bolt::Backend<Wire_T, Number_T> is a simple abstract class which must be implemented by the backend. It declares a number of methods which must be overridden by the backend. Each method handles a simple gate, such as @mul or @xor. WizToolKit guarantees that it will only call methods of one Gate Set. If an implementor can only handle one Gate Set it is acceptable to have empty or failing implementations for the other Gate Set.

typedef MyWire /* something that is default-constructible */;

struct MyBackend : public wtk::bolt::Backend<MyWire, uint64_t>
{
  void addGate(MyWire* const out, MyWire const* const left, MyWire const* const right) override
  {
    /* implementation */
  }

  void mulGate(MyWire* const out, MyWire const* const left, MyWire const* const right) override
  {
    /* implementation */
  }

  /* remaining methods omitted for brevity */
};

Assert Zero

The @assert_zero directive indicates that the proof would fail if its input were non-zero. The Backend API expects the implementor to cache assertions and check them at the end. This is done with a pair of assertZero(…​) and check() methods. Here is an example.

  bool failureCache = false;

  void assertZero(MyWire const* const wire) override
  {
    this->failureCache = (MyWire != 0) || this->failureCache;
  }

  bool check() override
  {
    return this->failureCache;
  }

The top-level caller may call check() at the top-level to check for failures. If shutdown code is necessary, it may be written in either the the finish() method or the destructor. The top-level caller must call finish() at the top level scope.

Replacing Exponentiation in Switch-Statements

By default, WizToolKit uses exponentiation (and Fermat’s Little Theorem) to test which case is selected in an arithmetic switch-statement. This means that there are n log(P) many additional multiplications per switch statement (n being number of cases and P being the prime). If an implementor’s ZK system can improve upon this, they may override the caseSelect(…​) function. The selected_bit output wire must be assigned 1 or 0 when the select_wire input wire is or is not equal to the case_number field-literal.

  void caseSelect(MyWire* const selected_bit,
      uint64_t const case_number, MyWire const* const select_wire) override
  {
    // Implement this
  }

Invoking BOLT

BOLT has two phases of invocation. First build translates the IR syntax tree to a more accelerated form, then evaluate processes the relation, invoking methods of the backend as necessary. Here is an example.

// Collect these from the parser
uint64_t characteristic = /* ... */;
bool is_boolean = /* ... */;
wtk::IRTree<uint64_t>* relation = /* ... */;
wtk::InputStream<uint64_t>* instance = /* ... */;
wtk::InputStream<uint64_t>* witness = /* ... */;

// Build the relation. *bolt_relation has the same lifetime as builder
wtk::bolt::Builder<MyWire, uint64_t> builder(characteristic);
wtk::bolt::Bolt<MyWire, uint64_t>* bolt_relation = builder.build(relation);

// Check that build succeeded and then evaluate.
if(bolt_relation != nullptr)
{
  // Evaluate the relation
  MyBackend backend(characteristic, is_boolean, /* ... */);
  wtk::bolt::Evaluator<MyWire, uint64_t> evaluator(&backend);

  if(!evaluator.evaluate(bolt_relation, instance, witness))
  {
    /* Instance or witness is poorly formed */
  }
  else if(!backend.check())
  {
    /* an assert zero failed, or other things happened to invalidate the proof */
  }
  else
  {
    /* success */
  }

  backend.finish();
}

At invocation time, it may be nonsensical for the a verifier to have a witness stream. To handle this, evaluate(…​) may be called with a nullptr. In this case, the evaluator will feed the backend zeroes in place of the witness.

  if(!evaluator.evaluate(bolt_relation, instance, nullptr))

Invoking PLASMASnooze

PLASMASnooze has just a single phase of execution. Instead of returning true/false for success or failure, it returns an enumeration indicating which resource caused the failure. As with BOLT, PLASMASnooze indicates only failures of each individual resource, leaving the backend to indicate failure of the proof.

// Collect these from the parser
uint64_t characteristic = /* ... */;
bool is_boolean = /* ... */;
wtk::IRTree<uint64_t>* relation = /* ... */;
wtk::InputStream<uint64_t>* instance = /* ... */;
wtk::InputStream<uint64_t>* witness = /* ... */;

// Evaluate the relation
MyBackend backend(characteristic, is_boolean, /* ... */);
wtk::bolt::PLASMASnooze<MyWire, uint64_t> snooze(&backend);

wtk::bolt::PLASMASnoozeStatus status =
  snooze.evaluate(relation, instance, witness);
if(wtk::bolt::PLASMASnoozeStatus::bad_relation == status)
{
  /* Relation is poorly formed */
}
if(wtk::bolt::PLASMASnoozeStatus::bad_stream == status)
{
  /* Instance or witness is poorly formed */
}
else if(!backend.check())
{
  /* an assert zero failed, or other things happened to invalidate the proof */
}
else
{
  /* success */
}

backend.finish();

Similarly to BOLT, PLASMASnooze may be invoked with a null witness, to feed a verifier zeroes in the place of witnesses.

wtk::bolt::PLASMASnoozeStatus status =
  snooze.evaluate(relation, instance, nullptr);

Streaming PLASMASnooze

A further optimization to PLASMASnooze, when processing strict IR-Simple, is to use the parser’s streaming API. When the relation is IR-Simple (a completely "flat" list of gates), the parser can pass each gate to a handler immediately after its parsed, rather than adding it to a syntax tree. The wtk::bolt::ArithmeticPLASMASnoozeHandler<Wire_T, Number_T> and wtk::bolt::BooleanPLASMASnoozeHandler<Wire_T> (Number_T is fixed as uint8_t) implement the Streaming API for PLASMASnooze. the check() method of each must be used to collect the status code (wtk::bolt::PLASMASnoozeStatus).

Here is an example invocation for arithmetic PLASMASnooze streaming.

// Collect these from the parser
uint64_t characteristic = /* ... */;
bool is_boolean = /* ... */;
wtk::ArithemticParser<uint64_t>* relation_parser = /* ... */;
wtk::InputStream<uint64_t>* instance = /* ... */;
wtk::InputStream<uint64_t>* witness = /* ... */;

// Evaluate the relation
MyBackend backend(characteristic, is_boolean, /* ... */);
wtk::bolt::ArithmeticPLASMASnoozeHandler<MyWire, uint64_t> snooze(&backend, instance, witness);

if(!relation_parser->parseStream(&snooze))
{
  /* Syntax error */
}
else
{
  wtk::bolt::PLASMASnoozeStatus status = snooze.check();
  if(wtk::bolt::PLASMASnoozeStatus::bad_relation == status)
  {
    /* Relation is poorly formed */
  }
  if(wtk::bolt::PLASMASnoozeStatus::bad_stream == status)
  {
    /* Instance or witness is poorly formed */
  }
  else if(!backend.check())
  {
    /* an assert zero failed, or other things happened to invalidate the proof */
  }
  else
  {
    /* success */
  }
}

backend.finish();

For verifiers, who have access to the instance but not the witness, the handler may be constructed with a nullptr witness.

wtk::bolt::ArithmeticPLASMASnoozeHandler<MyWire, uint64_t> snooze(&backend, instance, nullptr);

Appendix A: API Documentation

Parser API

Include this API as

#include <wtk/Parser.h>

Members of this API live in the following namespace

namespace wtk { ...

The Parser API is parameterized on a Number_T template. Number_T should be integer-like enough to be parsed from a string. This API is abstract and implemented by parsers for various IR formats.

template<typename Number_T> struct Parser

The Parser will read the IR’s front matter before delegating to an wtk::ArithmeticParser<Number_T> or a wtk::BooleanParser.

The struct’s public data members are set to default values (mostly 0) at construction and assigned concrete values as parse methods are invoked. The parser methods are expected to be called in the correct order (parseHeader(), parseResource(), and finally for relations only parseParameters()). A helper for calling them in the correct order is provided as parseHdrResParams().

When the front-matter has been parsed, one of arithmetic(), arithmetic64(), arithmetic32(), or boolean() may be invoked to delegate parsing the body to either of wtk::ArithemticParser<…​> or wtk::BooleanParser.

bool parseHeader()

Parses the resources header section setting the following attributes.

Returns true on success, false if a parse error occurs.

virtual bool parseHeader() = 0;
bool parseResource()

Parses the resource type and sets the wtk::Resource resource attribute.

Returns true on success, false if a parse error occurs.

virtual bool parseResource() = 0;
bool parseParameters()

Parses the relation’s parameters and sets the following attributes.

Returns true on success, false if a parse error occurs.

WARNING

parseParameters() should only be used if resource == wtk::Resource::relation.

virtual bool parseParameters() = 0;
bool parseHdrResParams()

This is a helper to call parseHeader(), parseResource(), and, if necessary, parseParameters() in sequence.

Returns true on success, false if a parse error occurs.

virtual bool parseHdrResParams() = 0;
struct { …​ } version

The version is the first line of an IR resource. Although WizToolKit tends to be tied to a particular IR version, the Parser does not make any checks for the particular IR version.

The version consists of major, minor, and patch elements, all of type size_t.

struct {
  size_t major = 0;
  size_t minor = 0;
  size_t patch = 0;
} version;
Number_T characteristic

The field’s prime modulus or "characteristic". The parser does not check for primality.

Number_T characteristic = Number_T(0);
size_t degree

The field’s degree. The IR requires this to be 1, although the parser does not test this.

size_t degree = 0;
wtk::Resource resource

The resource type which is currently being parsed. This has type wtk::Resource.

wtk::Resource resource = Resource::invalid;
wtk::GateSet gateSet

The set of gates to be allowed within the relation. This has type wtk::GateSet.

WARNING

gateSet may only be used if resource == wtk::Resource::relation.

wtk::GateSet gateSet;
wtk::FeatureToggles featureToggles

The IR structural features to be allowed within the relation. This has type wtk::FeatureToggles.

WARNING

featureToggles may only be used if resource == wtk::Resource::relation.

wtk::FeatureToggles featureToggles;
wtk::ArithemticParser<Number_T>* arithmetic()

This method returns a delegate parser for an arithmetic resource.

WARNING

When parsing a relation, use of an arithmetic parser for parsing a non-arithmetic gateset will result in parse errors.

void wtk::ArithmeticParser<Number_T>*  arithmetic() = 0;
wtk::ArithemticParser<uint64_t>* arithmetic()

This method returns a delegate parser for an arithmetic resource. However the Number_T template is downgraded to a uint64_t.

WARNING

When parsing a relation, use of an arithmetic parser for parsing a non-arithmetic gateset will result in parse errors.

void wtk::ArithmeticParser<uint64_t>*  arithmetic64() = 0;
wtk::ArithemticParser<uint32_t>* arithmetic()

This method returns a delegate parser for an arithmetic resource. However the Number_T template is downgraded to a uint32_t.

WARNING

When parsing a relation, use of an arithmetic parser for parsing a non-arithmetic gateset will result in parse errors.

void wtk::ArithmeticParser<uint32_t>*  arithmetic32() = 0;
wtk::BooleanParser* boolean()

This method returns a delegate parser for a boolean resource.

NOTE

The Number_T template is removed for wtk::BooleanParser, and uint8_t is always used in its place.

WARNING

When parsing a relation, use of a boolean parser for parsing a non-boolean gateset will result in parse errors.

void wtk::BooleanParser*  boolean() = 0;

template<typename Number_T> struct ArithmeticParser

This is a delegate parser for the body of an arithmetic IR resource. Its interface is substantially similar to wtk::BooleanParser. In general, this type should not be constructed, but rather obtained from parser.arithmetic().

bool parseStream(wtk::ArithmeticStreamHandler<Number_T>* handler)

Parses the body of an arithmetic IR-Simple relation, passing each gate off to the handler in a streaming fashion. The parser.resource must be wtk::Resource::relation.

The handler parameter must be nonnull. The method returns false on failure, including if either the parser.gateSet or parser.featureToggles are violated. It does not make any other well-formedness checks.

virtual bool parseStream(wtk::ArithmeticStreamHandler<Number_T>* handler) = 0;
wtk:IRTree<Number_T> parseTree()

Parses the body of any arithmetic relation, constructing a syntax tree. The parser.resource must be wtk::Resource::relation. If a parse failure occurs, nullptr is returned, including if either the parser.gateSet or parser.featureToggles are violated. It does not make any other well-formedness checks.

virtual wtk::IRTree<Number_T>* parseTree() = 0;
wtk::InputStream<Number_T>* instance()

Returns an wtk::InputStream<Number_T>* which will parse the instance one value at a time. The parser.resource must be wtk::Resource::instance.

This method will never return nullptr, instead returned wtk::InputStream<Number_T>* will return wtk::StreamStatus::error as necessary.

virtual wtk::InputStream<Number_T>* instance() = 0;
wtk::InputStream<Number_T>* shortWitness()

Returns an wtk::InputStream<Number_T>* which will parse the short witness one value at a time. The parser.resource must be wtk::Resource::shortWitness.

This method will never return nullptr, instead returned wtk::InputStream<Number_T>* will return wtk::StreamStatus::error as necessary.

virtual wtk::InputStream<Number_T>* shortWitness() = 0;

struct BooleanParser

This is a delegate parser for the body of an boolean IR resource. Its interface is substantially similar to wtk::ArithmeticParser<Number_T>. In general, this type should not be constructed, but rather obtained from parser.boolean(). Note that this struct is not parameterized by Number_T. Instead anywhere the a field/numeric literal would be expected, uint8_t is used instead.

bool parseStream(wtk::BooleanStreamHandler* handler)

Parses the body of an boolean IR-Simple relation, passing each gate off to the handler in a streaming fashion. The parser.resource must be wtk::Resource::relation.

The handler parameter must be nonnull. The method returns false on failure, including if either the parser.gateSet or parser.featureToggles are violated. It does not make any other well-formedness checks.

virtual bool parseStream(wtk::BooleanStreamHandler* handler) = 0;
wtk:IRTree<uint8_t> parseTree()

Parses the body of any arithmetic relation, constructing a syntax tree. The parser.resource must be wtk::Resource::relation. If a parse failure occurs, nullptr is returned, including if either the parser.gateSet or parser.featureToggles are violated. It does not make any other well-formedness checks.

virtual wtk::IRTree<uint8_t>* parseTree() = 0;
wtk::InputStream<uint8_t>* instance()

Returns an wtk::InputStream<uint8_t>* which will parse the instance one value at a time. The parser.resource must be wtk::Resource::instance.

This method will never return nullptr, instead returned wtk::InputStream<Number_T>* will return wtk::StreamStatus::error as necessary.

virtual wtk::InputStream<uint8_t>* instance() = 0;
wtk::InputStream<uint8_t>* shortWitness()

Returns an wtk::InputStream<uint8_t>* which will parse the short witness one value at a time. The parser.resource must be wtk::Resource::shortWitness.

This method will never return nullptr, instead returned wtk::InputStream<Number_T>* will return wtk::StreamStatus::error as necessary.

virtual wtk::InputStream<uint8_t>* shortWitness() = 0;

template<typename Number_T> struct InputStream

The InputStream represents either an instance or a short witness, and and allows the user to consume one value at a time from the stream. Do not attempt to construct one manually. Instead retrieve one from arithmeticParser.instance(), arithmeticParser.shortWitness(), booleanParser.instance(), or booleanParser.shortWitness().

StreamStatus next(Number_T* num)

Consumes a single value from the stream, placing it in the num parameter. This operation may fail if a parse error or the end of file is reached, returning an wtk::StreamStatus error code.

virtual StreamStatus next(Number_T* num) = 0;
size_t lineNum()

If the parser supports line numbering, then this method returns the line number corresponding to the prior invocation of this→next(…​). If line numbering is not supported then 0 is returned.

If this→next(…​) has not been called, it returned wtk::StreamStatus::end, or it returned wtk::StreamStatus::error then this→lineNum() may return any of 0, the line number on which the error or end occurred, or the line number of the most recent successful call to this→next(…​).

virtual size_t lineNum();

enum StreamStatus

This enumeration indicates the success or means of failure for an wtk::InputStream<Number_T>. It may take one of the following values.

wtk::StreamStatus::success

Successfully retrieved an item from the stream.

wtk::StreamStatus::end

Reached the end of the stream.

wtk::StreamStatus::error

A parse error occurred.

IR Tree API

Include this API as

#include <wtk/IRTree.h>

Members of this API live in the following namespace

namespace wtk { ...

The IR Tree API is parameterized on a Number_T template. Number_T should be integer-like enough to be parsed from a string. This API is abstract and implemented by parsers for various IR formats. As an abstract interface many "attributes" must be accessed through accessor methods due to different storage methods of various IR formats.

At a top level, the wtk::IRTree<Number_T> is the root of an abstract syntax tree for a relation in the SIEVE IR. The wtk::DirectiveList<Number_T> defines scope block within the AST and other structs such as wtk::BinaryGate defining individual directives.

Pointer members provided by the IR Tree API may be expected to be nonnull, taking the lifetime of the parser which provided a top-level wtk::IRTree<Number_T>*. However, as defined by the parser, the wtk::IRTree<Number_T>* may itself be null. The parser retains ownership of all objects from this API, the caller may not free(…​) them.

template<typename Number_T> struct IRTree

The wtk::IRTree<Number_T> struct is the root of an IR syntax tree. The encapsulates both a list of named functions and the top-level scope of an IR relation.

size_t size()

This method indicates how many named function declarations are defined by this relation. It is an integer greater than or equal to 0.

virtual size_t size() = 0;
wtk::FunctionDeclare<Number_T>* functionDeclare(size_t n)

Retrieve a named function declaration by index. n must be between 0 (inclusive) and this→size() (exclusive) or else undefined behavior occurs. It returns a nonnull wtk::FunctionDeclare<Number_T>*.

virtual wtk::FunctionDeclare<Number_T>* functionDeclare(size_t n) = 0;
wtk::DirectiveList<Number_T>* body()

Retrieve the body of the relation. It returns a nonnull wtk::DirectiveList<Number_T>*.

virtual wtk::DirectiveList<Number_T>* body() = 0;
size_t lineNum()

Returns the line number at which the IRTree begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct DirectiveList

The wtk::DirectiveList<Number_T> is a list type for directives. Since directives must be differentiated, each index of the list has a tag indicating a type, through which the element must be retrieved.

size_t size()

Indicates the number of elements in the list.

virtual size_t size() = 0;
enum Type

This enumerates the various types which an element may take.

wtk::DirectiveList<Number_T>::BINARY_GATE

corresponds to wtk::BinaryGate and this→binaryGate(n).

wtk::DirectiveList<Number_T>::UNARY_GATE

corresponds to wtk::UnaryGate and this→unaryGate(n).

wtk::DirectiveList<Number_T>::BINARY_CONST_GATE

corresponds to wtk::BinaryConstGate<Number_T> and this→binaryConstGate(n).

wtk::DirectiveList<Number_T>::INPUT

corresponds to wtk::Input and this→input(n).

wtk::DirectiveList<Number_T>::ASSIGN

corresponds to wtk::Assign<Number_T> and this→assign(n).

wtk::DirectiveList<Number_T>::ASSERT_ZERO

corresponds to a wtk::Terminal when used for the @assert_zero gate and this→assertZero(n).

wtk::DirectiveList<Number_T>::DELETE_SINGLE

corresponds to a wtk::Terminal when used for a @delete directive and this→deleteSingle(n).

wtk::DirectiveList<Number_T>::DELETE_RANGE

corresponds to an wtk::WireRange when used for a @delete directive and this→deleteRange(n).

wtk::DirectiveList<Number_T>::FUNCTION_INVOKE

corresponds to wtk::FunctionInvoke and this→functionInvoke(n).

wtk::DirectiveList<Number_T>::ANON_FUNCTION

corresponds to wtk::AnonFunction<Number_T> and this→anonFunction(n).

wtk::DirectiveList<Number_T>::FOR_LOOP

corresponds to wtk::ForLoop<Number_T> and this→forLoop(n).

wtk::DirectiveList<Number_T>::SWITCH_STATEMENT

corresponds to wtk::SwitchStatement<Number_T> and this→switchStatement(n).

wtk::DirectiveList<Number_T>::Type type(size_t n)

Returns the type of the nth element in this list. n must be in the range n >= 0 && n < this→size() otherwise undefined behavior occurs.

virtual Type type(size_t n) = 0;
wtk::BinaryGate* binaryGate(size_t n)

Returns the nth element as a wtk::BinaryGate type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::BINARY_GATE otherwise undefined behavior occurs.

virtual wtk::BinaryGate* binaryGate(size_t n) = 0;
wtk::UnaryGate* unaryGate(size_t n)

Returns the nth element as a wtk::UnaryGate type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::UNARY_GATE otherwise undefined behavior occurs.

virtual wtk::UnaryGate* unaryGate(size_t n) = 0;
wtk::BinaryConstGate<Number_T>* binaryConstGate(size_t n)

Returns the nth element as a wtk::BinaryConstGate<Number_T> type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::BINARY_CONST_GATE otherwise undefined behavior occurs.

virtual wtk::BinaryConstGate<Number_T>* binaryConstGate(size_t n) = 0;
wtk::Input* input(size_t n)

Returns the nth element as a wtk::Input type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::INPUT otherwise undefined behavior occurs.

virtual wtk::Input* input(size_t n) = 0;
wtk::Assign<Number_T>* assign(size_t n)

Returns the nth element as a wtk::Assign<Number_T> type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::ASSIGN otherwise undefined behavior occurs.

virtual wtk::Assign<Number_T>* assign(size_t n) = 0;
wtk::Terminal* assertZero(size_t n)

Returns the nth element as a wtk::Terminal type for the purpose of an @assert_zero gate. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::ASSERT_ZERO otherwise undefined behavior occurs.

virtual wtk::Terminal* assertZero(size_t n) = 0;
wtk::Terminal* deleteSingle(size_t n)

Returns the nth element as a wtk::Terminal type for the purpose of a @delete gate. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::DELETE_SINGLE otherwise undefined behavior occurs.

virtual wtk::Terminal* deleteSingle(size_t n) = 0;
wtk::WireRange* deleteRange(size_t n)

Returns the nth element as a wtk::WireRange type for the purpose of a @delete gate. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::DELETE_RANGE otherwise undefined behavior occurs.

virtual wtk::WireRange* deleteRange(size_t n) = 0;
wtk::FunctionInvoke* functionInvoke(size_t n)

Returns the nth element as a wtk::FunctionInvoke type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::FUNCTION_INVOKE otherwise undefined behavior occurs.

virtual wtk::FunctionInvoke* functionInvoke(size_t n) = 0;
wtk::AnonFunction<Number_T>* anonFunction(size_t n)

Returns the nth element as a wtk::AnonFunction<Number_T> type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::ANON_FUNCTION otherwise undefined behavior occurs.

virtual wtk::AnonFunction<Number_T>* anonFunction(size_t n) = 0;
wtk::ForLoop<Number_T>* forLoop(size_t n)

Returns the nth element as a wtk::ForLoop<Number_T> type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::FOR_LOOP otherwise undefined behavior occurs.

virtual wtk::ForLoop<Number_T>* forLoop(size_t n) = 0;
wtk::SwitchStatement<Number_T>* switchStatement(size_t n)

Returns the nth element as a wtk::SwitchStatement<Number_T> type. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::DirectiveList<Number_T>::SWITCH_STATEMENT otherwise undefined behavior occurs.

virtual wtk::SwitchStatement<Number_T>* switchStatement(size_t n) = 0;
size_t lineNum()

Returns the line number at which the DirectiveList begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct BinaryGate

This represents a binary gate in the IR. Binary refers to the two-input wires of this gate, not numeric representation. It has methods for left and right input wires as well as the output wire. The specific gate type is the Calculation enum.

enum Calculation

Indicates what calculation this gate performs.

wtk::BinaryGate::AND

@and

wtk::BinaryGate::XOR

@xor

wtk::BinaryGate::ADD

@add

wtk::BinaryGate::MUL

@mul

wtk::BinaryGate::Calculation calculation()

returns which calculation the binary gate performs.

virtual Calculation calculation() = 0;
wtk::index_t outputWire()

Returns the gate’s output wire.

virtual wtk::index_t outputWire() = 0;
wtk::index_t leftWire()

Returns the gate’s left input wire.

virtual wtk::index_t leftWire() = 0;
wtk::index_t rightWire()

Returns the gate’s right input wire.

virtual wtk::index_t rightWire() = 0;
size_t lineNum()

Returns the line number at which the binary gate begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct UnaryGate

This represents a unary gate in the IR. Unary refers to the single input wire of this gate, not numeric representation. It has methods for the input wire as well as the output wire. The specific gate type is the Calculation enum.

enum Calculation

Indicates what calculation this gate performs.

wtk::UnaryGate::NOT

$0 ← @not($1)

wtk::UnaryGate::COPY

$0 ← $1

wtk::UnaryGate::Calculation calculation()

returns which calculation the unary gate performs.

virtual Calculation calculation() = 0;
wtk::index_t outputWire()

Returns the gate’s output wire.

virtual wtk::index_t outputWire() = 0;
wtk::index_t rightWire()

Returns the gate’s input wire.

virtual wtk::index_t inputWire() = 0;
size_t lineNum()

Returns the line number at which the unary gate begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct BinaryConstGate

This represents a binary constant gate in the IR. Binary refers to the input wire and input constant of this gate, not numeric representation. It has methods for left input wire and right input constant as well as the output wire. The specific gate type is the Calculation enum.

enum Calculation

Indicates what calculation this gate performs.

wtk::BinaryConstGate<Number_T>::ADDC

@addc

wtk::BinaryConstGate<Number_T>::MULC

@mulc

wtk::BinaryConstGate<Number_T>::Calculation calculation()

returns which calculation the binary gate performs.

virtual Calculation calculation() = 0;
wtk::index_t outputWire()

Returns the gate’s output wire.

virtual wtk::index_t outputWire() = 0;
wtk::index_t leftWire()

Returns the gate’s left input wire.

virtual wtk::index_t leftWire() = 0;
wtk::index_t rightWire()

Returns the gate’s right input constant.

virtual Number_T rightValue() = 0;
size_t lineNum()

Returns the line number at which the binary constant gate begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct Input

Represents an input directive (either @instance or @short_witness). the Stream enumeration indicates from which stream to consume.

enum Stream

An enumeration of the IR stream resources.

wtk::Input::INSTANCE

@instance

wtk::Input::SHORT_WITNESS

@short_witness

wtk::Input::Stream stream()

Returns the stream from which this directive is to consume.

virtual Stream stream() = 0;
wtk::index_t outputWire()

Returns the stream consumption’s output wire.

virtual wtk::index_t outputWire() = 0;
size_t lineNum()

Returns the line number at which the input directive begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct Assign

A directive that assigns a constant value to an output wire.

wtk::index_t outputWire()

Returns the assign directive’s output wire.

virtual wtk::index_t outputWire() = 0;
Number_T constValue()

Returns the assign directive’s constant input value.

virtual Number_T constValue() = 0;
size_t lineNum()

Returns the line number at which the assign directive begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct Terminal

Represents a directive with just a single input wire. Its name is derived from the fact that it has no output wires, thus "terminating" some sequence of gates. It is used by the directives @assert_zero and @delete (for a single input wire), although they are distinguished by wtk::DirectiveList<Number_T>::Type rather than an enumeration within struct Terminal.

wtk::index_t wire()

Returns the terminal’s single input wire.

virtual wtk::index_t wire() = 0;
size_t lineNum()

Returns the line number at which the terminal begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct WireRange

Represents a range of wires in the IR. It is used for the range form of the @delete directive, as well as a component of the wtk::WireList.

wtk::index_t first()

Returns the first wire in the range (consider it inclusive).

virtual wtk::index_t first() = 0;
wtk::index_t last()

Returns the last wire in the range (consider it inclusive).

virtual wtk::index_t last() = 0;
size_t lineNum()

Returns the line number at which the wire range begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct WireList

The IR uses wire lists for holding parameters and returns to function-gates. These lists are "ranged" such that the elements of the list do not correspond to the length of the list. Some elements are individual wires, whereas other elements are ranges of wires. Element type is given by the Type enumeration.

size_t size()

Indicates how many elements are in the list (does not necessarily correspond to wire count).

virtual size_t size() = 0;
enum Type

Indicates if an element a single or a range element.

  • wtk::WireList::SINGLE

  • wtk::WireList::RANGE

wtk::WireList::Type type(size_t n)

Returns the type of the nth element. n must be in the range n >= 0 && n < this→size() or else undefined behavior occurs.

virtual Type type(size_t n) = 0;
wtk::index_t single(size_t n)

Returns the nth element in the list as a single element. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::WireList::SINGLE or else undefined behavior occurs.

virtual wtk::index_t single(size_t n) = 0;
wtk::WireRange* range(size_t n)

Returns the nth element in the list as a range element. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::WireList::RANGE or else undefined behavior occurs.

virtual wtk::WireRange* range(size_t n) = 0;
size_t lineNum()

Returns the line number at which the wire list begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct FunctionDeclare

This wtk::FunctionDeclare<Number_T> is the definition of a named function-gate. It pairs with wtk::FunctionInvoke for invocation. They should be matched to eachother by a name (as a char*).

char const* name()

Returns the name of the function.

virtual char const* name() = 0;
wtk::index_t outputCount()

Returns the number of output wires this function gate expects.

virtual wtk::index_t outputCount() = 0;
wtk::index_t inputCount()

Returns the number of input wires this function gate expects.

virtual wtk::index_t inputCount() = 0;
wtk::index_t instanceCount()

Returns the number of instance values this function gate will consume.

virtual wtk::index_t instanceCount() = 0;
wtk::index_t shortWitnessCount()

Returns the number of short witness values this function gate will consume.

virtual wtk::index_t shortWitnessCount() = 0;
wtk::DirectiveList<Number_T>* body()

returns the body of the function gate.

virtual DirectiveList<Number_T>* body() = 0;
size_t lineNum()

Returns the line number at which the function declaration begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct FunctionInvoke

The wtk:FunctionInvoke invokes a function gate, carrying a name which should match with the name of a wtk::FunctionDeclare<Number_T>.

char const* name()

Returns the name of the function gate.

virtual char const* name() = 0;
wtk::WireList* outputList()

Returns a wtk::WireList for the output wires of this invocation.

virtual wtk::WireList* outputList() = 0;
wtk::WireList* inputList()

Returns a wtk::WireList for the input wires of this invocation.

virtual wtk::WireList* inputList() = 0;
size_t lineNum()

Returns the line number at which the function invocation begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct AnonFunction

The wtk::AnonFunction<Number_T> is the simultaneous declaration and invocation of an anonymous function-gate. It mirrors the structure of both wtk::FunctionDeclare<Number_T> and wtk::FunctionInvoke, although without certain attributes such as name().

wtk::WireList* outputList()

Returns a wtk::WireList for the output wires of this anonymous function.

virtual wtk::WireList* outputList() = 0;
wtk::WireList* inputList()

Returns a wtk::WireList for the input wires of this anonymous function.

virtual wtk::WireList* inputList() = 0;
wtk::index_t instanceCount()

Returns the number of instance values this anonymous function gate will consume.

virtual wtk::index_t instanceCount() = 0;
wtk::index_t shortWitnessCount()

Returns the number of short witness values this anonymous function gate will consume.

virtual wtk::index_t shortWitnessCount() = 0;
wtk::DirectiveList<Number_T>* body()

returns the body of the anonymous function gate.

virtual DirectiveList<Number_T>* body() = 0;
size_t lineNum()

Returns the line number at which the anonymous function declaration begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct IterExpr

The wtk::IterExpr takes the place of wtk::index_t in input and output lists of For Loop bodies. Instead of representing an exact wire-index, these expressions evaluate to a wire-index, allowing the loop to traverse ranges of wires.

All iterator expressions are carried out over wtk::index_t. The expressions are a recursive datatype, with base cases for numeric literals and loop-iterators. Recursive cases exist for addition, subtraction, multiplication, and division by a constant. The expression type is given by enum Type.

enum Type

This enumerates the various types of expressions.

wtk::IterExpr::LITERAL

A numeric literal

wtk::IterExpr::ITERATOR

A reference to a loop iterator

wtk::IterExpr::ADD

Addition expression of two sub-expressions

wtk::IterExpr::SUB

Subtraction expression of two sub-expressions

wtk::IterExpr::MUL

Multiplition expression of two sub-expressions

wtk::IterExpr::DIV

Division expression of one sub-expression and a constant divisor

wtk:IterExpr::Type type()

Returns the type of this expression.

virtual Type type() = 0;
wtk::index_t literal()

Returns this literal expression or the right-hand-side of this division expression as a wtk::index_t. If the following precondition isn’t met, then undefined behavior occurs (see also this→type() and enum Type).

this->type() == wtk::IterExpr::LITERAL
  || this->type() == wtk::IterExpr::DIV
virtual wtk::index_t literal() = 0;
char const* name()

Returns this loop-iterator expression as a char*. If the following precondition isn’t met, then undefined behavior occurs (see also this→type() and enum Type).

this->type() == wtk::IterExpr::ITERATOR
virtual wtk::index_t literal() = 0;
wtk::IterExpr* lhs()

Returns the left-hand-side of this expression. If the following precondition isn’t met, then undefined behavior occurs (see also this→type() and enum Type).

this->type() == wtk::IterExpr::ADD
  || this->type() == wtk::IterExpr::SUB
  || this->type() == wtk::IterExpr::MUL
  || this->type() == wtk::IterExpr::DIV
virtual IterExpr* lhs() = 0;
wtk::IterExpr* lhs()

Returns the right-hand-side of this expression. If the following precondition isn’t met, then undefined behavior occurs (see also this→type() and enum Type).

this->type() == wtk::IterExpr::ADD
  || this->type() == wtk::IterExpr::SUB
  || this->type() == wtk::IterExpr::MUL
virtual IterExpr* lhs() = 0;
size_t lineNum()

Returns the line number at which the iterator expression begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct IterExprWireRange

Represents a range of iterator expressions, mirroring the form of wtk::WireRange. It is used as a component of the wtk::IterExprWireList (which itself mirrors wtk::WireList).

wtk::IterExpr* first()

Returns a wtk::IterExpr for the first wire in the range (consider it inclusive).

virtual wtk::IterExpr* first() = 0;
wtk::IterExpr* last()

Returns a wtk::IterExpr for the last wire in the range (consider it inclusive).

virtual wtk::IterExpr* last() = 0;
size_t lineNum()

Returns the line number at which the wire range begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct IterExprWireList

Represents a list of iterator expressions, mirroring the form of wtk::WireList. For for-loop bodies, the input and output wire lists use these to enable traversal based on the loop iterator.

These lists are "ranged" such that the elements of the list do not correspond to the length of the list. Some elements are individual expressions, whereas other elements are ranges of expressions. Element type is given by the Type enumeration.

size_t size()

Indicates how many elements are in the list (does not necessarily correspond to wire count).

virtual size_t size() = 0;
enum Type

Indicates if an element a single or a range element.

  • wtk::IterExprWireList::SINGLE

  • wtk::IterExprWireList::RANGE

wtk::IterExprWireList::Type type(size_t n)

Returns the type of the nth element. n must be in the range n >= 0 && n < this→size() or else undefined behavior occurs.

virtual Type type(size_t n) = 0;
wtk::ItereExpr* single(size_t n)

Returns the nth element in the list as a single element. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::IterExprWireList::SINGLE or else undefined behavior occurs.

virtual wtk::IterExpr* single(size_t n) = 0;
wtk::IterExprWireRange* range(size_t n)

Returns the nth element in the list as a range element. n must be in the range n >= 0 && n < this→size() and n must have the type this→type(n) == wtk::IterExprWireList::RANGE or else undefined behavior occurs.

virtual wtk::WireRange* range(size_t n) = 0;
size_t lineNum()

Returns the line number at which the wire list begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct IterExprFunctionInvoke

The wtk:IterExprFunctionInvoke invokes a function gate as the body of a for-loop, carrying a name which should match with the name of a wtk::FunctionDeclare<Number_T>. It mirrors wtk::FunctionInvoke replacing input and output lists with wtk::IterExprWireList.

char const* name()

Returns the name of the function gate.

virtual char const* name() = 0;
wtk::IterExprWireList* outputList()

Returns a wtk::IterExprWireList for the output wires of this invocation.

virtual wtk::IterExprWireList* outputList() = 0;
wtk::IterExprWireList* inputList()

Returns a wtk::IterExprWireList for the input wires of this invocation.

virtual wtk::IterExprWireList* inputList() = 0;
size_t lineNum()

Returns the line number at which the function invocation begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct IterExprAnonFunction

The wtk::IterExprAnonFunction<Number_T> is the simultaneous declaration and invocation of an anonymous function-gate as the body of a for-loop. It mirrors the structure of both wtk::FunctionDeclare<Number_T> and wtk::FunctionInvoke, although without certain attributes such as name(), and with the input and output lists replaced by wtk::IterExprWireList

wtk::IterExprWireList* outputList()

Returns a wtk::IterExprWireList for the output wires of this anonymous function.

virtual wtk::IterExprWireList* outputList() = 0;
wtk::IterExprWireList* inputList()

Returns a wtk::IterExprWireList for the input wires of this anonymous function.

virtual wtk::IterExprWireList* inputList() = 0;
wtk::index_t instanceCount()

Returns the number of instance values this anonymous function gate will consume.

virtual wtk::index_t instanceCount() = 0;
wtk::index_t shortWitnessCount()

Returns the number of short witness values this anonymous function gate will consume.

virtual wtk::index_t shortWitnessCount() = 0;
wtk::DirectiveList<Number_T>* body()

returns the body of the anonymous function gate.

virtual DirectiveList<Number_T>* body() = 0;
size_t lineNum()

Returns the line number at which the anonymous function declaration begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct ForLoop

This represents a for-loop directive in the IR.

wtk::WireList* outputList()

Returns the output list of the entire for-loop (not to be confused with the output list of one iteration of the for-loop) as a wtk::WireList.

virtual WireList* outputList() = 0;
char const* iterName()

Returns the name of the loop’s iterator.

virtual char const* iterName() = 0;
wtk::index_t first()

Returns the first iteration of the loop (inclusive).

virtual wtk::index_t first() = 0;
wtk::index_t last()

Returns the last iteration of the loop (inclusive).

virtual wtk::index_t last() = 0;
enum BodyType

An enumeration to indicate whether the loop’s body is named or anonymous.

wtk::ForLoop<Number_T>::INVOKE

Named body (use this→invokeBody() and wtk::IterExprFunctionInvoke).

wtk::ForLoop<Number_T>::ANONYMOUS

Anonymous body (use this→anonymousBody() and wtk::IterExprAnonFunction<Number_T>).

BodyType bodyType()

Returns the body type of this for-loop.

virtual BodyType bodyType() = 0;
wtk::IterExprFunctionInvoke* invokeBody()

Returns the body of this for-loop as an wtk::IterExprFunctionInvoke. If the loop’s body type is not this→bodyType() == wtk::ForLoop<Number_T>::INVOKE, then undefined behavior occurs.

virtual IterExprFunctionInvoke* invokeBody() = 0;
wtk::IterExprAnonFunction<Number_T>* anonymousBody()

Returns the body of this for-loop as an wtk::IterExprAnonFunction<Number_T>. If the loop’s body type is not this→bodyType() == wtk::ForLoop<Number_T>::ANONYMOUS, then undefined behavior occurs.

virtual IterExprAnonFunction<Number_T>* anonymousBody() = 0;
size_t lineNum()

Returns the line number at which the for-loop begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

struct CaseFunctionInvoke

The wtk:CaseFunctionInvoke invokes a function gate as the body of a switch-case. It mirrors the form of wtk::FunctionInvoke, however, as the body of a switch-case, it is missing outputList().

char const* name()

Returns the name of the function gate.

virtual char const* name() = 0;
wtk::WireList* inputList()

Returns a wtk::WireList for the input wires of this invocation.

virtual wtk::WireList* inputList() = 0;
size_t lineNum()

Returns the line number at which the function invocation begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct CaseAnonFunction

The wtk:CaseAnonFunction is the simultaneous declaration and invocation of an anonymous function-gate as the body of a switch-case. It mirrors the structure of both wtk::FunctionDeclare<Number_T> and wtk::FunctionInvoke, although without certain attributes such as name() or, as the body of a switch-case, outputList().

wtk::WireList* inputList()

Returns a wtk::WireList for the input wires of this anonymous function.

virtual wtk::WireList* inputList() = 0;
wtk::index_t instanceCount()

Returns the number of instance values this anonymous function gate will consume.

virtual wtk::index_t instanceCount() = 0;
wtk::index_t shortWitnessCount()

Returns the number of short witness values this anonymous function gate will consume.

virtual wtk::index_t shortWitnessCount() = 0;
wtk::DirectiveList<Number_T>* body()

returns the body of the anonymous function gate.

virtual DirectiveList<Number_T>* body() = 0;
size_t lineNum()

Returns the line number at which the anonymous function declaration begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct CaseBlock

This represents a case within a switch-statement.

Number_T match()

Returns the field-literal which is matched against the switch-statement’s condition() wire to indicate if this case is active.

virtual Number_T match() = 0;
enum BodyType

An enumeration to indicate whether the case’s body is named or anonymous.

wtk::CaseBlock<Number_T>::INVOKE

Named body (use this→invokeBody() and wtk::CaseFunctionInvoke).

wtk::CaseBlock<Number_T>::ANONYMOUS

Anonymous body (use this→anonymousBody() and wtk::CaseAnonFunction<Number_T>).

BodyType bodyType()

Returns the body type of this case block.

virtual BodyType bodyType() = 0;
wtk::CaseFunctionInvoke* invokeBody()

Returns the body of this case-block as a wtk::CaseFunctionInvoke. If the case’s body type is not this→bodyType() == wtk::CaseBlock<Number_T>::INVOKE, then undefined behavior occurs.

virtual CaseFunctionInvoke* invokeBody() = 0;
wtk::CaseAnonFunction<Number_T>* anonymousBody()

Returns the body of this case-block as a wtk::CaseAnonFunction<Number_T>. If the case’s body type is not this→bodyType() == wtk::CaseBlock<Number_T>::ANONYMOUS, then undefined behavior occurs.

virtual CaseAnonFunction<Number_T>* anonymousBody() = 0;
size_t lineNum()

Returns the line number at which the case-block begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

template<typename Number_T> struct SwitchStatement

This represents a switch-statement directive in the IR.

wtk::WireList* outputList()

Returns the switch-statement’s output list as a wtk::WireList.

virtual wtk::WireList* outputList() = 0;
wtk::index_t condition()

Returns the condition (or "selector") wire of this switch-statement.

virtual wtk::index_t condition() = 0;
size_t size()

Returns the number of cases in the switch-statement.

virtual size_t size() = 0;
wtk::CaseBlock<Number_T>* caseBlock(size_t n)

Returns the nth wtk::CaseBlock<Number_T> in this switch-statement. If n is outside of the range n >= 0 && n < this→size(), then undefined behavior occurs.

virtual CaseBlock<Number_T>* caseBlock(size_t n) = 0;
size_t lineNum()

Returns the line number at which the switch-statement begins. It may be unsupported by the parser (for example line numbering is nonsensical in a binary format), in which case 0 is always returned.

virtual size_t lineNum();

IRParameters API

Include this API as

#include <wtk/Parser.h>

Members of this API live in the following namespace

namespace wtk { ...

This header defines some of the front-matter parameters of the IR. Generally these parameters will be provided by the Parser API.

enum class Resource

An enumeration of the various resources an IR file may be.

  • wtk::Resource::relation

  • wtk::Resource::instance

  • wtk::Resource::shortWitness

  • wtk::Resource::invalid (a default or error condition)

struct GateSet

This structure defines the allowable gates of a relation. It is split along two varieties of gates arithmetic or boolean, each of which may be taken as a "cannonical" set (e.g. all gates enabled) or a subset.

enum { …​ } gateSet

This indicates which variety of gates are used. and has the following values

  • wtk::GateSet::arithmetic

  • wtk::GateSet::boolean

  • wtk::GateSet::invalid (a default or error conditions)

enum {
  arithmetic,
  boolean,
  invalid
} gateSet = invalid;
SubSet definitions (union)

This unnamed union attribute defines sub sets of either of the gate set varieties. As a union, only attributes of the active/correct gate set may be used.

Arithmetic Subsets (struct)

The following flags indicate if an arithmetic gate is allowable.

  • bool enableAdd indicates if @add is allowed.

  • bool enableAddC indicates if @addc is allowed.

  • bool enableMul indicates if @mul is allowed.

  • bool enableMulC indicates if @mulc is allowed.

Boolean Subsets (struct)

The following flags indicate if a boolean gate is allowable.

  • bool enableXor indicates if @xor is allowed.

  • bool enableAnd indicates if @and is allowed.

  • bool enableNot indicates if @not is allowed.

bool cannonical() const

A "cannonical" gate set is one which has all gates of the variety enabled. This function indicates if this GateSet is cannonical.

bool cannonical() const;

struct FeatureToggles

The IR allows structural features to be disabled. At the extremities "IR Simple" indicates that no features are enabled, while "IR Complete" indicates that all features are enabled.

bool functionToggle

This flag indicates that named functions are enabled, and that anonymous functions are allowed (except for the bodies of other enabled features).

bool functionToggle = false;
bool forLoopToggle

This flag indicates that for loops are enabled.

bool forLoopToggle = false;
bool switchCaseToggle

This flag indicates that switch statements are enabled.

bool switchCaseToggle = false;
bool simple() const

This method checks if these feature toggles form IR-Simple (all features disabled).

bool simple() const;
bool complete() const

This method checks if these feature toggles form IR-Complete (all features enabled).

bool complete() const;

Arithmetic Stream Handler API

Include this API as

#include <wtk/ArithmeticStreamHandler.h>

Members of this API live in the following namespace

namespace wtk { ...

This API is parameterized on a Number_T template. Number_T should be integer-like enough to be parsed from a string. This API is abstract and implemented by parsers for various IR formats.

template<typename Number_T> class ArithmeticStreamHandler

The wtk::ArithmeticStreamHandler<Number_T> is a virtual class for the user to implement with callbacks for the Parser API to use when stream parsing.

virtual void setLineNumber(size_t const line)

If the Parser supports line-numbering, it will use this callback to set the current line number before a gate’s callback is invoked.

virtual void setLineNum(size_t const line);
virtual void handleInstance(wtk::index_t const idx)

Called when an @instance directive is reached.

virtual void handleInstance(wtk::index_t const idx);
virtual void handleShortWitness(wtk::index_t const idx)

Called when an @short_witness directive is reached.

virtual void handleShortWitness(wtk::index_t const idx);
virtual void handleAdd(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right)

Called when an @add directive is reached.

virtual void handleAdd(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right);
virtual void handleMul(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right)

Called when an @mul directive is reached.

virtual void handleMul(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right);
virtual void handleAddC(wtk::index_t const out, wtk::index_t const left, Number_T const right)

Called when an @addc directive is reached.

virtual void handleAddC(wtk::index_t const out, wtk::index_t const left, Number_T const right);
virtual void handleMulC(wtk::index_t const out, wtk::index_t const left, Number_T const right)

Called when an @mulc directive is reached.

virtual void handleMulC(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right);
virtual void handleAssign(wtk::index_t const out, Number_T const val)

Called when a constant assignment directive is reached.

virtual void handleAssign(wtk::index_t const out, Number_T const val);
virtual void handleCopy(wtk::index_t const out, wtk::index_t const in)

Called when a copy directive is reached.

virtual void handleCopy(wtk::index_t const out, wtk::index_t const in);
virtual void handleAssertZero(wtk::index_t const in)

Called when an @assert_zero directive is reached.

virtual void handleAssertZero(wtk::index_t const in);
virtual void handleDeleteSingle(wtk::index_t const in)

Called when a @delete directive with a single argument is reached.

virtual void handleDeleteSingle(wtk::index_t const in);
virtual void handleDeleteRange(wtk::index_t const first, wtk::index_t const last)

Called when a @delete directive with a range argument is reached. The range is inclusive on both ends.

virtual void handleDeleteRange(wtk::index_t const first, wtk::index_t const last);
virtual void handleEnd()

Called after the last directive is reached.

virtual void handleEnd();

Boolean Stream Handler API

Include this API as

#include <wtk/BooleanStreamHandler.h>

Members of this API live in the following namespace

namespace wtk { ...

class BooleanStreamHandler

The wtk::BooleanStreamHandler is a virtual class for the user to implement with callbacks for the Parser API to use when stream parsing.

virtual void setLineNumber(size_t const line)

If the Parser supports line-numbering, it will use this callback to set the current line number before a gate’s callback is invoked.

virtual void setLineNum(size_t const line);
virtual void handleInstance(wtk::index_t const idx)

Called when an @instance directive is reached.

virtual void handleInstance(wtk::index_t const idx);
virtual void handleShortWitness(wtk::index_t const idx)

Called when an @short_witness directive is reached.

virtual void handleShortWitness(wtk::index_t const idx);
virtual void handleXor(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right)

Called when an @xor directive is reached.

virtual void handleXor(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right);
virtual void handleAnd(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right)

Called when an @and directive is reached.

virtual void handleAnd(wtk::index_t const out, wtk::index_t const left, wtk::index_t const right);
virtual void handleNot(wtk::index_t const out, wtk::index_t const in)

Called when a @not directive is reached.

virtual void handleNot(wtk::index_t const out, wtk::index_t const in);
virtual void handleAssign(wtk::index_t const out, uint8_t const val)

Called when a constant assignment directive is reached.

virtual void handleAssign(wtk::index_t const out, uint8_t const val);
virtual void handleCopy(wtk::index_t const out, wtk::index_t const in)

Called when a copy directive is reached.

virtual void handleCopy(wtk::index_t const out, wtk::index_t const in);
virtual void handleAssertZero(wtk::index_t const in)

Called when an @assert_zero directive is reached.

virtual void handleAssertZero(wtk::index_t const in);
virtual void handleDeleteSingle(wtk::index_t const in)

Called when a @delete directive with a single argument is reached.

virtual void handleDeleteSingle(wtk::index_t const in);
virtual void handleDeleteRange(wtk::index_t const first, wtk::index_t const last)

Called when a @delete directive with a range argument is reached. The range is inclusive on both ends.

virtual void handleDeleteRange(wtk::index_t const first, wtk::index_t const last);
virtual void handleEnd()

Called after the last directive is reached.

virtual void handleEnd();

ANTLR Parser API

Include this API as

#include <wtk/antlr/Parser.h>

Members of this API live in the following namespaces

namespace wtk { namespace antlr { ...

The Parser API is parameterized on a Number_T template. Number_T should be integer-like enough to be parsed from a string. This API is abstract and implemented by parsers for various IR formats.

template<typename Number_T> struct Parser

The wtk::antlr::Parser<Number_T> implements the wtk::Parser<Number_T>. It parses text and produces line numbering. However, the ANTLR runtime has been known to use large quantities of memory. Additionally, it cannot truly stream parse either IR-Simple or input streams (instance/short witness). While, it does implement the parseStream(…​) API, it must read the entire relation ahead of time.

Parser(std::string& f_name)

Constructor via opening the file named by f_name. Undefined behavior occurs if the file does not exist.

Parser(std::string& f_name);

IRRegular Parser API

Include this API as

#include <wtk/irregular/Parser.h>

Members of this API live in the following namespaces

namespace wtk { namespace irregular { ...

The Parser API is parameterized on a Number_T template. Number_T should be integer-like enough to be parsed from a string. This API is abstract and implemented by parsers for various IR formats.

template<typename Number_T> struct Parser

The wtk::irregular::Parser<Number_T> implements the wtk::Parser<Number_T>. It parses text but does not produce line numbering. It is designed to minimize memory usage while maximizing parser speed. It is capable of stream-parsing, although it does require some buffering.

Parser(std::string& f_name)

Constructor via opening the file named by f_name. Undefined behavior occurs if the file does not exist.

Parser(std::string& f_name);
Parser(FILE* f)

Constructor which uses a FILE*. Undefined behavior occurs if f is nullptr or f is not opened to an existing file (e.g. not a directory).

Parser(FILE* f);

FlatBuffer Parser API

Include this API as

#include <wtk/flatbuffer/Parser.h>

Members of this API live in the following namespaces

namespace wtk { namespace flatbuffer { ...

The Parser API is parameterized on a Number_T template. Number_T should be integer-like enough to be parsed from a string. This API is abstract and implemented by parsers for various IR formats.

template<typename Number_T> struct Parser

The wtk::flatbuffer::Parser<Number_T> implements the wtk::Parser<Number_T>. It parses binary and consequently line-numbering is nonsensical. It cannot truly stream parse either IR-Simple or input streams (instance/short witness) because FlatBuffers is designed around random access of a buffer. While, it does implement the parseStream(…​) API, it must read the entire relation ahead of time. It could (but does not) stream segments of a very large resource (>2GB) because these resources are split into multiple FlatBuffers.

Parser(std::string& f_name)

Constructor via opening the file named by f_name. Undefined behavior occurs if the file does not exist.

Parser(std::string& f_name);

BOLT Builder API

Include this API as

#include <wtk/bolt/Builder.h>

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> struct Builder

The wtk::bolt::Builder<Wire_T, Number_T> conducts the first stage of BOLT invocation — building an augmented/annotated syntax tree. It does its best to do this in O(s) time where s is the size of the syntax-tree. This is easy to do for most of the IR, however, certain classes of for-loops require work proportional to either number of iterations ("soft" unrolling), or proportional to iterations and size of the sub-syntax tree ("hard" unrolling).

Builder(Number_T const c)

The only constructor for a wtk::bolt::Builder<Wire_T, Number_T> requires just a single Number_T parameter for the circuit’s characteristic (prime modulus).

Builder(Number_T const c);
Bolt<Wire_T, Number_T>* build(wtk::IRTree<Number_T>* const tree)

This method builds a wtk::bolt::Bolt<Wire_T, Number_T> tree from the wtk::IRTree<Number_T> parameter. It returns nullptr when the tree violates IR well-formedness semantics. In the case that tree == nullptr then undefined behavior occurs. Multiple invocations of build(…​) on the same object will result in undefined behavior.

wtk::bolt::Bolt<Wire_T, Number_T>* build(wtk::IRTree<Number_T>* const tree);

BOLT Evaluator API

Include this API as

#include <wtk/bolt/Evaluator.h>

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.

class Evaluator

The wtk::bolt::Evaluator<Wire_T, Number_T> class encapsulates the second phase of BOLT invocation. It traverses the BOLT relation and "executes" each gate. Thus, it is by definition O(n) where n is the total number of gates.

Evaluator(wtk::bolt::Backend<Wire_T, Number_T>* const b)

The single constructor requires just a pointer to the wtk::bolt::Backend<Wire_T, Number_T> implementation.

Evaluator(wtk::bolt::Backend<Wire_T, Number_T>* const b);
bool evaluate(wtk::bolt::Bolt<Wire_T, Number_T>* const bolt, wtk::InputStream<Number_T>* const instance, wtk::InputStream<Number_T>* const witness)

Evaluates a wtk::bolt::Bolt<Wire_T, Number_T> relation and returns true on success. The bolt relation may be constructed using the BOLT Builder. It must also have two wtk::InputStream<Number_T>s. The first, instance, must not be nullptr, while the second, witness, may be nullptr for the cases where the witness is inaccessible to a verifier.

bool evaluate(Bolt<Wire_T, Number_T>* const bolt,
    wtk::InputStream<Number_T>* const instance,
    wtk::InputStream<Number_T>* const witness);

BOLT Backend API

Include this API as

#include <wtk/bolt/Backend.h>

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);
virtual bool check() = 0

This method is to be called by the caller (rather than the BOLT Builder or Evaluator. After the Evaluator completes successfully, this function should be called to indicate if evaluation validity holds for the witnessed-statement.

virtual bool check() = 0;
virtual void finish()

This method is to be called by the caller (rather than the BOLT Builder or Evaluator. After the Evaluator completes (successfully or not), this function must be called to perform cleanup tasks.

virtual void finish() { }

PLASMASnooze

Include this API as

#include <wtk/bolt/PLASMASnooze.h>

Members of this API live in the following namespace

namespace wtk { namespace bolt { ...

The PLASMASnooze Interpreter 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. PLASMASnooze requires the Wire_T to be default constructible/destructable as well as mutable/overwritable.

The PLASMASnooze API is an IR interpreter sharing the Backend API. It runs in a single pass and ignores certain deviations from the IR Specification, where they are deemed harmless. The name PLASMASnooze is derived from FIREALARM. PLASMA is an improvement upon FIRE (in the sense of performance and pluggability of ZK Backends), while Snooze is the opposite of ALARM (in the sense of ignoring harmless deviations from the IR Spec). The acryonym expands to Practical Local Acceleration for Single-pass with Malleable Assumtions Snooze.

template<typename Wire_T, typename Number_T> class PLASMASnooze

The wtk::bolt::PLASMASnooze<Wire_T, Number_T> is a main driver object. It walks an IR syntax tree and, at each gate, invokes a corresponding gate handler from the Backend API.

PLASMASnooze(wtk::bolt::Backend<Wire_T, Number_T>* const b)

The constructor requires just a pointer to a wtk::bolt::Backend<Wire_T, Number_T>.

PLASMASnooze(wtk::bolt::Backend<Wire_T, Number_T>* const b);
wtk::bolt::PLASMASnoozeStatus evaluate(wtk::IRTree<Number_T>* const rel_tree, wtk::InputStream<Number_T>* const ins_stream, wtk::InputStream<Number_T>* const wit_stream)

Evaluates an wtk::IRTree<Number_T> relation and returns an enum wtk::bolt::PLASMASnoozeStatus. It must also have two wtk::InputStream<Number_T>s. The first, instance, must not be nullptr, while the second, witness, may be nullptr for the cases where the witness is inaccessible to a verifier.

PLASMASnoozeStatus evaluate(
    wtk::IRTree<Number_T>* const relation,
    wtk::InputStream<Number_T>* const instance,
    wtk::InputStream<Number_T>* const witness);

enum class PLASMASnoozeStatus

This is an enumeration of statuses that PLASMASnooze can return.

wtk::bolt::PLASMASnooze::bad_relation

The relation is poorly-formed.

wtk::bolt::PLASMASnooze::bad_stream

The instance or witness is poorly-formed.

wtk::bolt::PLASMASnooze::well_formed

The relation, witness, and instance are all well-formed.

Arithmetic PLASMASnooze Streaming API

Include this API as

#include <wtk/bolt/ArithmeticPLASMASnoozeHandler.h>

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. PLASMASnooze requires it to be default constructible/destructible, and mutable/overwritable.

template<template Wire_T, typename Number_T> class ArithmeticPLASMASnoozeHandler

The wtk::bolt::ArithmeticPLASMASnoozeHandler<Wire_T, Number_T> implements the wtk::ArithmeticStreamHandler<Number_T> abstract class with callbacks for interpreting wire-numbers and making calls to the wtk::bolt::Backend<Wire_T, Number_T> callback API.

ArithmeticPLASMASnoozeHandler(wtk::bolt::Backend<Wire_T, Number_T>* const b, wtk::InputStream<Number_T>* const ins, wtk::InputStream<Number_T>* const wit)

The constructor requires a wtk::bolt::Backend<Wire_T, Number_T>* for ZK callbacks, as well as two wtk::InputStream<Number_T>* parameters for the instance and short witness. The second input stream (short witness) may be nullptr, as may be necessary for verifier implementations.

ArithmeticPLASMASnoozeHandler(
    wtk::bolt::Backend<Wire_T, Number_T>* const b,
    wtk::InputStream<Number_T>* const ins,
    wtk::InputStream<Number_T>* const wit);
wtk::Bolt::PLASMASnoozeStatus check()

After stream parsing/processing the check() method retrieves a status (wtk::PLASMASnoozeStatus).

wtk::bolt::PLASMASnoozeStatus check();

Boolean PLASMASnooze Streaming API

Include this API as

#include <wtk/bolt/BooleanPLASMASnoozeHandler.h>

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. For Boolean relations, this is fixed to uint8_t.

Wire_T

This template is an opaque structure supplied by the Backend for encapsulating data related to a wire. PLASMASnooze requires it to be default constructible/destructible, and mutable/overwritable.

template<template Wire_T, typename Number_T> class BooleanPLASMASnoozeHandler

The wtk::bolt::BooleanPLASMASnoozeHandler<Wire_T, Number_T> implements the wtk::BooleanStreamHandler abstract class with callbacks for interpreting wire-numbers and making calls to the wtk::bolt::Backend<Wire_T, uint8_t> callback API.

BooleanPLASMASnoozeHandler(wtk::bolt::Backend<Wire_T, uint8_t>* const b, wtk::InputStream<uint8_t>* const ins, wtk::InputStream<uint8_t>* const wit)

The constructor requires a wtk::bolt::Backend<Wire_T, uint8_t>* for ZK callbacks, as well as two wtk::InputStream<uint8_t>* parameters for the instance and short witness. The second input stream (short witness) may be nullptr, as may be necessary for verifier implementations.

BooleanPLASMASnoozeHandler(
    wtk::bolt::Backend<Wire_T, uint8_t>* const b,
    wtk::InputStream<uint8_t>* const ins,
    wtk::InputStream<uint8_t>* const wit);
wtk::Bolt::PLASMASnoozeStatus check()

After stream parsing/processing the check() method retrieves a status (wtk::PLASMASnoozeStatus).

wtk::bolt::PLASMASnoozeStatus check();