Execution strategies

June 10, 2026 · View on GitHub

Every circuit in emp-ag2pc runs on one session, AG2PCSession, through the same five protocol passes (backend/pass_ctx.h) with identical security, communication, and per-gate cost. There are three ways to feed a circuit to those passes. They differ only in how the gate stream is produced and in their memory/latency trade-offs.

AG2PCSession sess(io, &pool, party);
using Ctx = AG2PCSession::DirectCtx;
using UInt32 = UInt_T<Ctx, 32>;
auto a = sess.input<UInt32>(ALICE, x);
auto b = sess.input<UInt32>(BOB, y);

The session owns the I/O boundary and the crypto; sess.direct_ctx() is the gate context (AG2PCSession::DirectCtx) the values are built over.

DirectCtx is only the direct/user operator-mode context — the recorder where a + b and frontend::run(sess.direct_ctx(), …) emit gates. A session is multipass: it owns several internal pass contexts that the engine drives, and a single canonical "session ctx" for all phases does not exist. In compiled replay the circuit is recorded over RecordCtx and replayed through those internal pass contexts; in live-body replay the body is re-instantiated over each pass context per pass. A materialized direct value is just wires/ids over DirectCtx; the pass contexts are not user-visible.

1. Direct / chunked

sess.direct_ctx() is a BooleanContext: operators on its values (a + b) record gates into the current chunk. The chunk runs through the engine when you reveal or checkpoint.

auto z = a + b;                    // recorded, pending
auto out = sess.reveal(z, PUBLIC); // flush the chunk, then open z

emp-tool's generic frontend::run(sess.direct_ctx(), circuit, args...) and frontend::run(body, args...) also drive the gate context's ops, so they too emit direct gates into the current chunk — convenient, but not a standalone pass replay. Prefer sess.run(...) (below) when you want a self-contained replay.

Best for imperative / reactive programs and large compositions chunked with checkpoint.

2. Compiled replay

Compile a pure body once with the emp-tool frontend, then replay the stored program standalone through all passes:

auto c = frontend::compile<rec::UInt<32>, rec::UInt<32>>(
    [](auto x, auto y) { return x + y; });
auto z = sess.run(c, a, b);        // standalone pass replay

Best for fixed circuits compiled once and replayed many times.

3. Live body replay

Replay a pure body live, once per pass, with no stored IR. Argument value types are deduced from the arguments:

auto z = sess.run([](auto x, auto y) { return x + y; }, a, b);

sess.run is one overloaded call: hand it a compiled Circuit (strategy 2) or a pure body (strategy 3) and the right one runs, selected at compile time on frontend::is_circuit_v. Best for one-off pure circuits and the leanest memory profile. A live body replay and the compiled replay of the same body produce a byte-identical protocol transcript — both drive the same pass definitions over the same gate stream. This is the regression gate test_body_replay_equiv.

Materialized vs pending arguments

sess.run(...) is a standalone replay: its arguments must be materialized — produced by sess.input / sess.input_batch, a prior run, or carried through a checkpoint. A value that is still pending in the open direct chunk must be flushed first (sess.checkpoint(v)); passing a pending value is a hard error. (Mixing a direct-chunk value directly into a standalone run is a deferred feature.)

Raw programs

For the genuinely-untyped case — a hand-authored or loaded BooleanProgram (e.g. an AES/SHA .empbc builtin) that carries no typed signature (no RetV/ArgVs value types), so it cannot be wrapped as a typed frontend::Circuit — the advanced escape sess.run_artifact<RetV>(program, args...) replays it over materialized typed arguments, returning a value of type RetV. Use BitVec (or the raw protocol() bit path) for wide crypto I/O — never a UInt clear codec beyond 64 bits. Prefer wrapping a fixed program into a typed frontend::Circuit and calling sess.run(circuit, ...); reach for run_artifact only when the signature is truly untyped.