# Arithmetic share runtime {#arith_runtime} \htmlonly
ELI5. Beside FSS keys you get ordinary secret shares: add them locally, multiply with Beaver or RSS, flip between bits and numbers with edaBits, and truncate fixed-point products. The composer schedules those opens next to FSS walks.
\endhtmlonly Semi-honest 2PC and honest-majority 3PC. Openings may carry Shark/SPDZ IT-MACs from the beaver session. A leaf that must enter a boolean netlist uses [b2y / a2y](@ref yao_leaf) and comes back with `y2b` / `y2a`. There is no Yao domain on the composer. ## Domains | Domain | Meaning | | --- | --- | | `a` / `b` / `fss` | Existing additive, subtractive, FSS leaf | | `rss` / `y` | Existing replicated / product factor | | `bin` | (2,2) XOR bit shares (packed) | | `bin_rss` | (2,3) replicated bits | `composer::as` never casts to or from `bin` / `bin_rss`. Use `bin_a2b` / `bin_b2a` / `bin_inject` (see [compose.hpp](@ref dpf/compose.hpp) opcodes 400–405). ## Building blocks | Header | Role | | --- | --- | | [rss_seed.hpp](@ref dpf/rss_seed.hpp) | Pairwise PRG seeds, zero-sharing, RSS mul local | | [ot_pack.hpp](@ref dpf/ot_pack.hpp) | Consumable B2A / bit pads or dealer dabits | | [edabit.hpp](@ref dpf/edabit.hpp) | daBits and edaBits; A2B | | [bit_inject.hpp](@ref dpf/bit_inject.hpp) | Bit × arithmetic (2PC / RSS) | | [trunc.hpp](@ref dpf/trunc.hpp) | Probabilistic and exact truncate; mul_trunc | | [share_cmp.hpp](@ref dpf/share_cmp.hpp) | Share–share compare, ReLU, max, range, div | | [share_vec.hpp](@ref dpf/share_vec.hpp) | Lane-block share vectors | | [fixed_share.hpp](@ref dpf/fixed_share.hpp) | `fixed` | | [share_expr.hpp](@ref dpf/share_expr.hpp) | Imperative recorder | | [gilboa.hpp](@ref dpf/gilboa.hpp) | One-off product / tape fill | | [matmul.hpp](@ref dpf/matmul.hpp) | Matrix triples and matmul | | [shuffle.hpp](@ref dpf/shuffle.hpp) | Hidden reorder of an RSS column. A secret index stays a DPF | | [arith_garble.hpp](@ref dpf/arith_garble.hpp) | Free add and a unary projection, after a word has left the key | | [flute.hpp](@ref dpf/flute.hpp) | Public table on short masked bits. A DPF point stays a key | | [cost_pass.hpp](@ref dpf/cost_pass.hpp) | DCF vs edaBit vs A2B strategy | | [yao.hpp](@ref dpf/yao.hpp) | Half-gates netlist on a leaf's XOR bits. Party 0 garbles | | [yao_share.hpp](@ref dpf/yao_share.hpp) | Leaf share to those bits and back (`b2y`, `a2y`, `fss2y`, `rss2y`) | | [yao_aes.hpp](@ref dpf/yao_aes.hpp) | The PRG's zero-key MMO block, and AES-128 under a shared key | ## When to use which comparison - **One input public or keyed:** DCF / `geneval_*` / interval keys. - **Both inputs arithmetic shares:** `share_cmp` (mask, open, MSB / DCF at the public difference). - **The leaf must enter a deep bit circuit:** [Yao](@ref yao_leaf). Not a comparison, a mux, or a public-offset LUT. ## A small word after the key {#arith_garble_word} Comparisons, intervals, and public-offset polynomials stay on the key. [Grotto](@ref jet_and_ring) covers a public offset. This section is the word you already hold as shares, when the next step is addition, a public scale, or a unary map, and you do not want an opening between the gates. [arith_garble.hpp](@ref dpf/arith_garble.hpp) is that circuit ([Ball, Malkin, and Rosulek, CCS 2016](@ref bib_garble_gadgets)). Addition is free. Scaling by a public constant coprime to the modulus is free. A unary map of a mod-`m` wire sends `m − 1` ciphertexts. A threshold of `b` bits that already live in `Z_{b+1}` is one such map, so the row count is `b`. A product in a small prime field is the discrete-log reduction: project to the exponent, add, project back, and drop the zero cases. The beaver [session](@ref beaver_triples) is the other tool. It opens one masked wire and multiplies interactively. It does not garble these gadgets. ```cpp dpf::arith_garble::circuit c; auto x = c.input(7); auto y = c.input(7); c.out(c.mul(c.add(x, y), x)); auto opened = dpf::arith_garble::eval_pair(c, in); ``` `opened.mask` is the garbler's share and `opened.color` is the evaluator's. `open_shares` subtracts them mod the output modulus. ## A public table on short shares {#flute_lut} A secret point in a public table is a DPF dotted with that table. FLUTE is the case where the index is already a handful of masked bits sitting in an ABY2.0 or three-party XOR sharing, and the result has to stay in that sharing. [flute.hpp](@ref dpf/flute.hpp) follows Brüggemann, Hundt, Schneider, Suresh, and Yalame, [IEEE S&P 2023](@ref bib_flute). The table is an inner product of those bits. The online exchange is two bits per output bit for two parties, and three bits per output bit for `eval_trio`, independent of how wide the index is. The index is at most 8 bits. Bit 0 of the index is the least significant bit of the row. ```cpp auto pair = dpf::flute::eval_pair(delta, n_out, columns, bits); auto trio = dpf::flute::eval_trio(delta, n_out, columns, bits); ``` `columns[w * 2^δ + row]` is output bit `w` on that row. `opened` is the clear bit. `masked` XOR the party's mask shares is the same bit. ## An array of shares, not a secret index {#share_shuffle} A secret index is a DPF. One read of a shared memory is a unit key, a public rotate, and a dot product, as in [3-party Duoram](@ref app_duoram). The shuffle is the other job: the parties already hold a share of every row, and the next step opens values. The opened order must not be the stored order. `shuffle_party` derives one permutation from `k01` and applies it to every component. A caller who passes the whole seed bundle can recompute that order. Use it when the order is allowed to be known. `shuffle_hidden_pass` is the order no single party should learn. Three passes use the pairwise seeds `k01`, `k12`, and `k20`, leaving out the party who does not hold that seed (party 2, then 0, then 1). Each party is given `rss::party_seeds` only. On a pass, the two parties who share the seed permute a two-party split of the column. The left-out party sends nothing and receives one fresh component. Both messages go to the sender's RSS neighbor. `permute` means `out[i] = in[pi[i]]`. Replaying the clear column is `π01`, then `π12`, then `π20`. ```cpp auto opened = dpf::shuffle::shuffle_hidden_triple(column, bundle, /*index=*/0); ``` `composer::shuffle_hidden(n, value_bytes)` records those three exchanges as `shuffle_send`. `aux` on each node is the left-out party. This is for a column you already share: a Duoram memory before a bulk open, a histogram, a PSI payload. It does not replace a key. One hidden cell is still a DPF. A comparison or a sort by a secret key is a DCF or `share_cmp`. A gather to data-dependent indices is a DPF per access. The seed permutation is chosen before the data. ## Truncation - `trunc_prob` — local right shift, error in `{0,1}`, no round. - `trunc_exact` — edaBit / carry correction. - `mul_trunc` — product then shift (fixed-point multiply). ## Networking `schedule_round` carries `phase::{setup,online}`, `round_dir::{duplex,send_next,recv_prev}`, and `receive_rule::ring_next`. `drive_options` adds `pipeline_credit`, `cleartext`, and `check_open`. Pairwise seeds replace `dealer_zero` via `rss_zero_mask`. **Go deeper:** [Beaver](@ref beaver_triples), [compose](@ref protocol_compose), [Grotto carry](@ref jet_and_ring).