L0 Bytecode / DKLS23
DKLS23 L0 bytecode
ShareMulBackendOt is a single L1 instruction. At L0, the DKLS23 path realizes it through five ordered stages: MRR21 seed OT setup, SoftSpoken OT extension, RVOLE, share multiplication finalization, and a consistency witness. Each stage is visible in the trace.
S_beta = (Sigma, L, W_beta, R_beta, Q_beta); op_beta(C, roots, S_beta) -> (root, S_beta', effects)Intuition: share_mul takes two values that are each split across the nodes and produces a split share of their product, with no node ever holding either input in the clear. The instruction list below is the fixed order every node follows — set up oblivious transfer (MRR21 seed, then SoftSpoken extension), run the RVOLE exchange, finalize its product share, and check a consistency witness before the result is sealed. Each instruction is exactly one of three kinds: a local computation, a point-to-point message, or a frontier where the node waits for a peer.
Each instruction shows descriptors for locality, phase, and stage. The uppercase badges state what the step does to state; locality remains the security-relevant descriptor for local, p2p, frontier, and evidence movement.
01root := H_step(C, op, [left_cid, right_cid])- Append MicroStepRecord with seed phase.
- Create seed_send_root for sender-side setup material.
- Keep execution inside witness construction; no peer frontier.
02root := H_step(C, op, [seed_send_root, right_cid])- Append MicroStepRecord with seed phase.
- Create seed_recv_root and SeedMaterial receiver_seed.
- Bind anti_replay := H(execution_id, roster_hash, lane, site, self_peer, seed roots).
03leaf_i := F(C, pprf/leaf, [seed_send_root, seed_recv_root, anti_replay], i)- Build PprfState leaves.
- Record pprf_root := cid(PprfState).
- Prepare deterministic OT extension material for later witness checks.
04choice_i := lsb(H(left_cid, right_cid, site, self_peer)[i]); selected_i := leaf_i + (choice_i ? 1 : 0)- Build PprfEvalState choices and selected leaves.
- Record pprf_eval_root.
- Bind receiver choices to input roots and local peer context.
05round1 := { receiver_commitment: H(site, pprf_eval_root, choices), choice_digest: H(choices) }- Produce ssot_round1_root.
- Mark pending_capability=true.
- Project to ShareMulOtRound::SsotRound1Recv wire traffic.
06pair_i := { zero: leaf_i + F(zero-mask, [r1], i), one: selected_i + x + F(one-mask, [r1], i) }- Produce sender_commitment over masked_pairs.
- Record ssot_round2_root.
- Mark pending_capability=true and project to SsotRound2Send wire traffic.
07mask_i := selected_i + F(receiver-mask, [left_cid], i); delta := sum(mask_i)- Build RvoleReceiverState { x, masks, delta }.
- Record rvole_recv_root.
- Keep receiver-side scalar input local to the witness path.
08a_i := leaf_i; b_i := pair_i.zero + pair_i.one + F(sender-bias, [right_cid], i); c_i := a_i * y + b_i- Build RvoleSenderState { y, correlations }.
- Record rvole_send_root.
- Mark pending_capability=true and project to RvoleSendProc wire traffic.
09product := x * y; receiver_fragment := F(finalize/receiver-fragment, [left_cid, right_cid], 0); sender_fragment := product - receiver_fragment- Build AdditiveFragments with result := receiver_fragment + sender_fragment.
- Record finalize_root.
- Prepare the local share scalar that will be committed by execution_delta.
10ok := (product == result); tag := H(transcript_root, product, result, ok)- Build ConsistencyCheck and check_root.
- Create trace_cid := cid(records) and witness_handle := H(C, trace_cid).
- execution_delta commits Sigma share value + BackendMicroTrace and L witness bytes + local scalar.
seed_ot_recv_initSeedOtRecvInitseed setup / receiverseed OT batch round1 payloadseed_ot_send_initSeedOtSendInitseed setup / senderseed OT batch round2 payloadssot_round1_recvSsotRound1Recvpending frontierSoftSpokenRound1 or forced-reuse round1ssot_round2_sendSsotRound2Sendpending frontierSoftSpokenRound2 or forced-reuse round2rvole_send_procRvoleSendProcpending frontierRVOLE sender processing payloadWhat the bytecode realizes
At L1, ShareMulBackendOt is a stable semantic operation: two secret-shared scalar inputs, one additive share of their product as output. At L0, the DKLS23 backend realizes that through OT machinery. The L0 path records micro-ops and trace records so the L1-to-bytecode lowering claim is independently reviewable.
Forced-reuse state lifecycle
In the forced-reuse path, the MRR21 seed OT setup runs inside each share-mul session rather than as a separate preprocessing batch. This is a deliberate performance tradeoff: the setup phase is visible in the session and avoids a separate coordination round. The handle chain is explicit: OtBaseBatchHandle → OteExtensionHandle → ShareMulPreprocHandle → ShareMulSessionHandle, each produced and consumed in order.
The backend tracks each setup object through its lifecycle: role-bound local state, then consumed in share_mul, then finalized or poisoned after conflict or misuse. That explicit lifecycle is how the architecture detects forced-reuse violations before secret material is used: a poisoned handle is a closed state that carries an evidence record.
Public versus private data
Wire envelopes, typed records, schema tags, and public witness roots go into replicated state or evidence. Raw seeds, OT secrets, local deltas, nonce-like material, and secret witness state stay in the local backend or secret-kernel-owned store. Product systems observe L0 bytecode through performance records, witness roots, and evidence handles, while raw intermediate values stay local.
Instruction calculus
All families share the same transition shape: S_beta = (Sigma, L, W_beta, R_beta, Q_beta). Sigma is replicated state, L is local secret material, W_beta is the family witness store, R_beta is ordered trace evidence, and Q_beta is the pending peer frontier.
DKLS23 opcodes are phase-sized because the meaningful review boundaries are seed, SSOT, RVOLE, finalize, and check, which sit above the substep level. An opcode boundary is justified when a substep has its own failure class, peer frontier, secret-boundary crossing, or audit artifact.