Skip to main content
Version: Next (unstable)

Multiset checks

A multiset check proves that two collections contain the same elements with the same multiplicities, regardless of order. Both virtual tables and communication buses have these semantics. This page presents the standard running-product construction for intuition; Miden VM enforces its multiset relations with LogUp.

Running product columns​

One way to compare two vectors aa and bb as multisets is to use a single running-product column:

  • The running product column is initialized to a value xx at the beginning of the trace. (We typically use x=1x = 1.)
  • All values of aa are multiplied into the running product column.
  • All values of bb are divided out of the running product column.
  • If aa and bb were multiset equal, then the running product column will equal xx at the end of the trace.

The row values are encoded using random challenges α0,α1,…\alpha_0, \alpha_1, \ldots sent to the prover after it commits to the execution trace.

Virtual tables​

Virtual tables can be used to store intermediate data which is computed at one cycle and used at a different cycle. When the data is computed, the row is added to the table, and when it is used later, the row is deleted from the table. Thus, all that needs to be proved is the data consistency between the row that was added and the row that was deleted.

The consistency of a virtual table can be proved with a single trace column pp, which keeps a running product of rows that were inserted into and deleted from the table. This is done by reducing each row to a single value, multiplying the value into pp when the row is inserted, and dividing the value out of pp when the row is removed. Thus, at any step of the computation, pp contains a product of all rows currently in the table.

The initial value of pp is set to 1. If the table is empty when the computation finishes, the final value of pp is also 1. Boundary constraints enforce these initial and final values.

Computing a virtual table's trace column​

To compute a product of rows, each row is first reduced to a single value.

Let t0,t1,t2,...t_0, t_1, t_2, ... be columns in the virtual table, and assume the verifier sends a set of random values α0\alpha_0, α1,...\alpha_1, ... to the prover after the prover commits to the execution trace of the program.

The prover reduces row ii in the table to a single value rir_i as:

ri=α0+α1⋅t0,i+α2⋅t1,i+α3⋅t2,i+...r_i = \alpha_0 + \alpha_1 \cdot t_{0, i} + \alpha_2 \cdot t_{1, i} + \alpha_3 \cdot t_{2, i} + ...

Then, when row ii is added to the table, we'll update the value in the pp column like so:

p′=p⋅rip' = p \cdot r_i

Analogously, when row ii is removed from the table, we'll update the value in column pp like so:

p′=prip' = \frac{p}{r_i}

Virtual tables in Miden VM​

Miden VM's virtual-table relations retain the insertion-and-removal semantics above, but their auxiliary columns use the signed LogUp construction rather than a running product.

Communication buses​

A communication bus can be modeled as a multiset equality between requests and responses. In a running-product realization, a single trace column bb records the communication as follows:

  • Each request is encoded from the operation type, inputs, and outputs, then divided out of the running-product column bb.
  • Each provider response encodes the same data and is multiplied into bb.

Thus, if the requests and responses match, and the bus column bb is initialized to 11, then bb will start and end with the value 11. This condition is enforced by boundary constraints on column bb.

Note that the order of the requests and responses does not matter, as long as they are all included in bb. In fact, requests and responses for the same operation will generally occur at different cycles. Additionally, there could be multiple requests sent in the same cycle, and there could also be a response provided at the same cycle that a request is received.

Communication bus constraints​

These constraints have two requirements:

  • The lookup value must be computed using random values α0,α1\alpha_0, \alpha_1, etc. that are provided by the verifier after the prover has committed to the main execution trace.
  • The lookup value must include all uniquely identifying information for the component/operation and its inputs and outputs.

Given an example operation opexop_{ex} with inputs i0,...,ini_0, ..., i_n and outputs o0,...,omo_0, ..., o_m, the lookup value can be computed as follows:

lookup=α0+α1⋅opex+α2⋅i0+...+αn+2⋅in+αn+3⋅o0+...+αn+2+m⋅omlookup = \alpha_0 + \alpha_1 \cdot op_{ex} + \alpha_2 \cdot i_0 + ... + \alpha_{n+2} \cdot i_n + \alpha_{n+3} \cdot o_0 + ... + \alpha_{n + 2 + m} \cdot o_m

The constraint for sending this to the bus as a request would be:

b′⋅lookup=bb' \cdot lookup = b

The constraint for sending this to the bus as a response would be:

b′=b⋅lookupb' = b \cdot lookup

However, these constraints must be combined, since it's possible that requests and responses both occur during the same cycle.

To combine them, let ulookupu_{lookup} be the request value and let vlookupv_{lookup} be the response value. These values are both computed the same way as shown above, but the data sources are different, since the input/output values used to compute ulookupu_{lookup} come from the trace of the component that's "offloading" the computation, while the input/output values used to compute vlookupv_{lookup} come from the trace of the specialized component.

The final constraint can be expressed as:

b′⋅ulookup=b⋅vlookupb' \cdot u_{lookup} = b \cdot v_{lookup}

Communication buses in Miden VM​

The native VM execution proof applies these multiset semantics to typed relations among the Core, Chiplets, Eidos compression, and And8 lookup AIRs. It uses domain-separated LogUp: providers emit positive fractions, consumers emit matching negative fractions, and the verifier checks their cross-AIR balance. See LogUp usage in Miden VM for the encoding, per-relation sign conventions, and closure equations.