Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ACE chiplet

The following note describes the design and functionality of the Arithmetic Circuit Evaluation (ACE) chiplet.

Given a description of an arithmetic circuit and a set of input values, it ensures this circuit evaluates to zero over these inputs. Its main purpose is to reduce the number of cycles required when recursively verifying a STARK proof in Miden assembly. In particular, it performs the DEEP-ALI constraint composition polynomial check over the evaluations of the trace column polynomials at the out-of-domain point.

The chiplet expects the caller to have prepared a region of memory containing

  • inputs to circuit,
  • constants which make up the circuit,
  • instructions describing the arithmetic operations evaluated by the circuit.

The term variable refers to a value, which is either an input or a constant.

Mathematically, we can represent an arithmetic circuit as a DAG, where leaves correspond to inputs and constants, and the nodes are the operations computing the result (which must be zero). For example, take the following composition polynomial to be evaluated by the chiplet

Given an input selector , and input variables , the two combined constraints ensure that

The following graph describes the evaluation of the circuit describing the above polynomial. The leaf nodes correspond to the variables of the polynomial: blue for inputs and green for constants. Note that the circuit is able to reuse evaluation, as is the case for the node .

flowchart BT
    %% Sink node (final expression)
    add2["result = c₀ + α⋅c₁"]
    mul1["s × (s−1)"]
    mul4["α × c₁"]
    add1["c₁ = s⋅case₌₁ + (s−1)⋅case₌₀"]
    mul2["s × case₌₁"]
    mul3["(s−1) × case₌₀"]
    sub1["s − 1"]
    sub2["case₌₁ = output − 42"]
    sub4["case₌₀ = output − input"]
    %% Leaf nodes
    s["s"]
    one1["1"]
    alpha["α"]
    input["input"]
    const42["42"]
    output_val["output"]
    %% Classes: colored borders only
    classDef blue stroke: #3498db, stroke-width: 2px;
    classDef green stroke: #2ecc71, stroke-width: 2px;
    class s,alpha,input,output_val blue;
    class one1,const42 green;
    %% Edges (pointing upward)
    mul1 --> add2
    mul4 --> add2
    s --> mul1
    sub1 --> mul1
    s --> sub1
    one1 --> sub1
    alpha --> mul4
    add1 --> mul4
    mul2 --> add1
    mul3 --> add1
    s --> mul2
    sub2 --> mul2
    output_val --> sub2
    const42 --> sub2
    sub1 --> mul3
    sub4 --> mul3
    output_val --> sub4
    input --> sub4

The chiplet constructs and verifies the correctness of such a DAG by using a logUp argument, which we interpret as a wiring bus. In each row, the chiplet can either insert a new node with the next fresh identifier and desired value or request a node’s value by providing the identifier of a previously inserted node. Whenever we create a new node in the DAG (when loading a variable or evaluating an operation), we “insert” it onto the wiring bus by emitting a tuple together with its final fan‐out count . In other words, at insertion time we record with multiplicity , where is exactly the number of times this node will later be used as an input to downstream operations. Then, each time some later instruction reads that node , we “consume” one copy of - i.e., we remove it once from the wiring bus — decrementing the stored multiplicity by exactly 1. By the time we finish inserting and consuming all nodes, two things must hold:

  1. The very last node we produced (the root of the DAG) has value 0.
  2. Every inserted tuple has been consumed exactly times, so the wiring bus is empty.

Trace layout

The ACE chiplet produces a trace with 16 internal columns. Each section of the trace corresponds to exactly one circuit evaluation.
Within each section, there are two ordered blocks:

  1. A READ block, which loads inputs/constants from memory and inserts them into the DAG.
  2. An EVAL block, which executes each instruction — fetching two existing DAG nodes, computing , and inserting a new node.

In what follows, we'll refer to READ/EVAL blocks depending on which operation is being performed in a given row, though we sometimes refer to a row's mode when it would conflict with the term operation.

Columns

The following table describes the 16 columns used by the chiplet, and their interpretation in each block.

BLOCK
READ============
EVAL============
  • "=" means the interpretation is the same in both READ/EVAL.
  • Empty cell means the cell is unused in this block.
  • Unlabeled columns appear under a block‐specific heading instead.

While we will later describe the purpose of each comment, we provide some intuition about how to interpret the labels themselves:

  • is a boolean selector indicating the first row of a section,
  • is a boolean selector indicating the type of block the row is a part of (0 for READ, and 1 for EVAL),
  • identifies the memory request when reading variables or circuit instructions.
  • refers to a node in the evaluation graph at index whose value is the extension field element , for .
  • is used when inserting a node into the evaluation graph, corresponding to its fan-out degree. It is also interpreted as the multiplicity of the element being added to the wiring bus.

Memory layout

The chiplet trace contains multiple sections, each performing a distinct circuit evaluation.
Within a section, the chiplet reads through a contiguous, word‐aligned memory region that contains:

  • input variables each stored as an extension‐field element, with two elements per word.
  • circuit constants also stored two per word, which are part of the circuit description and hence included in its commitment.
  • circuit instructions each encoded as one field‐element representing a packed triple .

The caller is responsible for writing the inputs and circuit into memory before invoking the chiplet.
If the same circuit is evaluated multiple times, the caller must overwrite the input region with the new inputs for each evaluation.
To start a circuit evaluation, the caller pushes one chiplet‐bus message:
where:

  • identifies the memory‐access context that every row will use.
  • is the word-aligned pointer to the first input variable.
  • is the total count of input and constant elements that the chiplet will read.
  • is the total number of arithmetic operations (instructions) the chiplet will evaluate.

For both inputs and constants, it is permissible to pad their respective regions with zeros.
Any padded zero will simply be ignored by the instructions (they are not referenced by any instruction, so their multiplicity will be set to 0). To ensure the entire region is word-aligned, we add up to three "dummy" instructions which square the last node. This has no effect when the last evaluation is zero, as required.

Circuit evaluation

The evaluation is initialized in the first row of the section by setting

  • , indicating the expected number of nodes in the DAG. Whenever the chiplet adds a new wire to the bus, this identifier decrements by 1, until it reaches 0.
  • , indicating the start of the section (it is set to 0 in all remaining rows)
  • , ensuring the evaluation starts by reading variables
  • provided by the bus request. remain constant for the entire section, while is constant only across the READ block.

In every row, the chiplet the following actions in each block:

READ (when ):

  • Reads a word from memory at , containing two extension-field elements .
  • Assigns two new node IDs to those elements, where
  • Inserts each new node into the evaluation graph (wiring bus) with a specified fan-out count .
  • Increments by 4 in the next row.
  • Decrements by 2 in the next row.
  • If in the next row is equal to , it switches to the EVAL operation by setting

EVAL (when ):

  • Reads a single field-element (an encoded instruction) from memory at .
  • Decodes from .
  • Fetches the two input nodes from the wiring bus, consuming one fan-out from each (i.e., with multiplicity ).
  • Computes
  • Inserts onto the wiring bus with its final fan-out count .
  • Increments by 4 in the next row.
  • If , checks that and ends the evaluation.
  • Otherwise, decrements by 1 in the next row.

Note: Wire bus requests also include the memory access pair which ensures that the wires produced by different circuit evaluations are distinct.

Example

The following is a section of the trace representing the evaluation of the expressions

We start by assigning values to both the inputs and constants nodes, stored in memory in addresses 0x0000 - 0x0005

We can then write down the values of all evaluated nodes. Their instructions are stored in the memory region 0x0006 - 0x00014

//
10ctx0x0000clk14138
00ctx0x0004clk12118
00ctx0x0008clk1098
01ctx0x000cclk81292
01ctx0x000dclk71281
01ctx0x000eclk613101
01ctx0x000fclk513111
01ctx0x0010clk41261
01ctx0x0011clk3851
01ctx0x0012clk2431
01ctx0x0013clk11421
01ctx0x0014clk0710

Constraints

Flags

In this section, we derive boolean flags that indicate whether a row is at the boundary (first, last, or transition) of the ACE chiplet trace, a section, or a READ/EVAL block.

Chiplet flags

The chiplet trace activates different chiplet constraints using a common set of binary selectors . While it is likely that the ACE chiplet will appear in third position, we derive the flags and boundary constraints for the general case where the chiplet appears in the d-th position. Accounting for this degree allows us to evaluate whether we need a separate degree-1 internal selector for activating the chiplet's constraints. The layout of the chiplet trace will look something like the following.

Chiplet...
Previous
ACE
Next

From these common selectors, we derive the following binary flags which indicate which portion of the ACE chiplet is active.

  • : The previous chiplet is active.
  • : The ACE chiplet is active.
  • : Next row is the first row in ACE chiplet.
  • : Current and next rows are in ACE chiplet.
  • : Last row in ACE chiplet.

Section and block flags

The selector indicates the start of a new section, from which we can derive the following flags indicating which part of the section the current row is in:

  • : the current row initializes the section.
  • : the current and next rows are in the same section.
  • : the current row finalizes the section.

These flags require the following constraints on .

  • it is binary.
  • it must equal 1 in the first row.
  • it must equal 0 in the last row.
  • two consecutive rows cannot initialize a section, so a section contains at least two rows.

A section is composed of a READ block followed by an EVAL block. The flag indicating which block is active is derived from the binary selector . These constraints ensure they are mutually exclusive

The following constraints ensure the proper layout of the trace. In particular, it contains one or more sections each with consecutive READ and EVAL blocks.

  • The first row cannot be EVAL, so it must be READ.
  • A row after EVAL cannot be READ.
  • The last row cannot be READ, so it must be EVAL.

In particular, we can infer from the above that

  • each section contains at least two rows (a READ and an EVAL row), and,
  • a row following a READ is always in the same section.

A READ row checks whether in the next row is equal to provided by the caller at initialization, in which case we ensure the following row is an EVAL. Otherwise, remains the same.

Section constraints

These constraints apply to all rows within the same section/

  • Across the section, and are constant.
  • A READ/EVAL block requests a word/element from memory, so the increases by 4/1, respectively in the next row.
  • A READ/EVAL block adds 2/1 new nodes to the evaluation graph, so decreases by that amount in the next row.

READ constraints

In a READ block, each row requests a row from memory a word containing two extension field elements and . The wire bus section describes how both of these nodes are inserted into the wire bus.

The only constraint we enforce is that and are consecutive

EVAL constraints

An EVAL block checks that the arithmetic operation was correctly applied to inputs and results in . The result is given by the degree-4 expression

The output node is correctly evaluated when:

  • is a valid arithmetic operation, and,
  • is equal to .

The actual instruction is given by the field element read from memory. It encodes

  • the operation using 2 bits
  • the ids of and using 30 bits each and are packed as

It is clear from the constraint on that will always require 2 bits, and that range constraints on are unnecessary. These ids are sent as-is to the wire bus with multiplicity . For the logUp argument to be valid, the section must include a row where a node is added to the circuit with the same id such that the pole can be annihilated. The only way to do so is if there exists a corresponding matching the one in the instruction. This is ensured by the pointers given by the chiplet bus message initializing the section, and the constraint enforcing it to be strictly increasing in each row. Therefore, as long as the trusted circuit contains fewer than ids, the and values can never overflow this bound.

To ensure the circuit has finished evaluating and that the final output value is 0, we enforce that the node with has value in the last row of the section.

Wire bus

Each row of the chip makes up to 3 requests to the circuit's wire bus. For , each request has the form , which uniquely identifies a node in the DAG representing the evaluation of the circuit. Sending this message to the bus can be viewed as updating the total degree of the node in the graph. When performing a READ operation, a node is added to the graph, and we set its degree update to be equal to its final fan-out degree at the end of the evaluation. This value is also referred to as the multiplicity . When a node is used as an input of an arithmetic operation, we set .

The expression is derived from and the operation flag, so that the wire bus update is uniform across all rows of the chiplet's trace.

  • always defines a new node, and each operation defines its identifier and multiplicity using the same columns.

  • defines a new node when the operation is a READ, but is an input during an EVAL. Again, the columns for these values are identical.

  • is unused during a READ, and an input during EVAL

The auxiliary logUp bus column is updated as follows. Given random challenges for , let be the randomized node value. The value of the bus in the next column is given by

The actual constraint is given by normalizing the denominator

Chiplet and Virtual table bus

The ACE chiplet initializes a circuit evaluation by responding to a request made by the decoder, through the chiplet bus . As mentioned earlier, the message corresponds to the tuple, which is sent to the bus only when . The value is computed as , since in the first row, is expected to be equal to the total number of nodes inserted (subtracting 1 since identifiers are indexed from zero). We refer to the chiplet bus constraints which describes the constraints for chiplet bus responses.

The requests sent to the memory chiplet cannot use the same chiplet bus, as the decoder requests saturate the degree of constraint over its auxiliary column. Instead, we use the virtual table bus which extends the chiplet bus.

In each row, the chiplet makes one of the two following requests to the memory chiplet depending on which block it is in:

  • , when .
  • , when .

The values are obtained as-is from the current row, except for the instruction which is given by As mentioned earlier, it encodes a circuit instruction applying the arithmetic operation (mapped to the range ) to the nodes with identifiers .

As usual, the messages are randomly reduced using by challenges , resulting in the degree-1 expressions and , respectively.

Since the virtual table bus is used exclusively by the chiplets trace, it must be constrained in this chiplet: