Audit

Summary

Scope & commit pinning. The VIA-C findings (A1–A8) below were performed at commit 9575286, and every source link in that section stays pinned there. VIA-B (the batch variant) was merged upstream later (PR #10, commit 62fe493), behind the via-b cargo feature; it is covered by a dedicated follow-up pass — VIA-B (batch) follow-up — pinned to 62fe493. See the Implementation details page for the codebase as built.

This audit confirms the parameter and noise-budget concerns that external reviewers (Yue et al.) raised in the VIA Security review thread.1 In short: the shipped "realistic" parameters use the paper's draft gadget bases (not the authors' later erratum), the security level is a hard-coded unbacked 128 inconsistent with both the paper's claimed 110 and the reviewers' measured 72–88 bits, there is no correctness test under the paper's actual noise distributions and database dimensions, and the "realistic" Gaussian key distribution declared in the presets is inert: every test actually runs ternary keys. The follow-up parameterization work adds a scheme-level finding (A9): the paper's DMux/CMux noise bound omits the secret \(\mathbb E[s^2]\) factor, so its intended Gaussian-key parameters fail \(2^{-40}\): now confirmed empirically and analytically in-repo. A derived \(\ge120\)-bit SECURE_PARAMS preset now clears security with margin (estimator-gated), though its correctness margin is thin and ternary-dependent. On the credit side, two suspected issues are refuted: the VIA-C plaintext modulus is correctly \(p=16\), and the secret-dependent decode step is constant-time.

Scope. This page audits implementation / code quality: what the Rust does, where it diverges from the paper, what is tested, and what is constant-time. The parameter question (paper vs reality: the security and correctness numbers, the modulus chain, the draft-vs-erratum gadgets) now lives in the Params section, where it is backed by the in-repo via-estimator crate. Where a finding below is fundamentally about parameters (A1, A2, A5), it links across to the reconciled, estimator-backed treatment there rather than duplicating it.

VIA-C audit findings

Severity: critical breaks security/correctness · high serious flaw · medium hazard/coverage gap · low. Each states confidence. The crypto-core scope only; no HTTP/auth layer exists to review. Source links pinned to commit 9575286.

highA1 — Shipped gadget bases are the paper's draft Table 6 values, not the corrected erratum presets.rs:150,153,156 · paper Table 6, p.23

code REALISTIC_PARAMS ships three runtime gadget bases — DMux 55879 (:150), CMux 81 (:153), ring-switch 8 (:156) — identical to the paper's printed Table 6 (p.23); the conversion key carries length \(\ell=18\) (there is no separate runtime conversion-base field).2 But the authors' May-11 erratum states those were "inadvertently left at draft values" and the correct VIA-C bases are DMux 18073, CMux/rot 307, rs 4 (and conversion base 11) — only with which they compute \(\log_2 P_{\text{fail}}\approx-43.4\).3 The decomposition lengths \(\ell\) (2,2,8,18) are unchanged, so performance is unaffected, but the noise budget is governed by the bases. inference The code therefore ships a parameter set whose correctness the authors do not claim meets the \(2^{-40}\) target.

code Update: this is no longer just a paper-vs-code base mismatch: the in-repo via-estimator now proves the shipped draft bases miss \(2^{-40}\) (test draft_gadgets_fail_correctness) and reproduces the authors' \(-43.4\) only with the erratum bases. And it shows that simply rebasing is not sufficient at the secure dimensions: the binding lever is the DMux / L_QUERY gadget length \(\ell\!:\!2\to3\), not the base (see A9 and Params · Concrete).

Confidence: high — bases read directly from code and cross-checked against both the printed table and the erratum; line numbers and Table-6 page (p.23) re-verified. Fix: adopt the erratum bases and the DMux \(\ell\!\to\!3\) bump; gate on the in-repo \(P_{\text{fail}}\) calc.

highA2 — Hard-coded security_param = 128 is unbacked and inconsistent with the paper (110) and reviewers (72–88) presets.rs:164 · params.rs:116

code The field is stored as a plain u32 and read nowhere except for printing/asserts.4 paper §5.1 claims 110 bits via the lattice estimator.5 unverified External reviewers ran the implementation parameters through the OpenFHE estimator and obtained ~88 (big ring) / ~72 (small ring).1 The code asserting a higher number (128) than the paper's own claim, with no derivation, is a config hazard.

code Update: there is now an in-repo estimator: the via-estimator crate (added during this audit) runs a calibrated core-SVP estimate on the shipped presets and gates CI. On the ternary keys the code actually uses, it reports ~77 bits (binding small ring) for REALISTIC_PARAMS, so the asserted 128 is not merely underived but wrong by ~50 bits. The full parameter-security reconciliation (paper vs review vs this estimate) now lives on the Params · Concrete page; what remains here, as a code-quality defect, is the hard-coded, unvalidated constant itself.

Confidence: high. Fix (partially done): via-estimator now gates CI on a real estimate; the remaining step is to derive security_param from it rather than carry a separate hard-coded constant.

mediumA3 — No empirical correctness test at the paper's noise distributions and database dimensions (the analytic \(2^{-40}\) budget now exists; an at-scale end-to-end witness does not) client_server_e2e_paper.rs:42-43,69-71,146

code A paper-scale round-trip test passes (I ran it: 2 passed, 35.7s release) and asserts the right record — but it is #[ignore]d (off by default), uses ternary keys/error (not the paper's discrete-Gaussian \(\sigma_{1,S}{=}32,\ \sigma_{1,E}{=}1024\) on the big ring, \(\sigma{=}26\) on the small ring), and runs a 2×2 database (\(\log I=\log J=1\)) versus the paper's \(I=2^8\!-\!2^{11},\,J=2^{12}\!-\!2^{14}\).6 Since noise grows with \(\log I,\log J\) and the first-dimension \(I\,n_1\) accumulation, a 2×2 ternary run exercises essentially none of the budget. code All benches are toy-scale.7

code Update: the missing analytic budget now exists: via-estimator::noise implements the Appendix-C \(P_{\text{fail}}\) recursion (validated: it reproduces the authors' \(-43.4\) exactly at the paper's \(n_1{=}2048\)) and gates CI. With Yue's correction — the DMux/CMux residual scales with \(\mathbb E[s^2]\), which Lemmas C.1/C.2 omit — it shows the paper's intended Gaussian-key design fails \(2^{-40}\) outright (the bound was too aggressive), while via-rs's ternary keys make SECURE_PARAMS clear it on a thin margin (details on Params · Concrete). What is still missing is an empirical end-to-end correctness test at paper noise/dimensions; the analytic gap is closed.

Confidence: high. Fix (partially done): analytic noise budget added (via-estimator); still need a paper-noise, paper-dimension empirical correctness test run by default at ≥1 DB size.

mediumA4 — "Realistic" Gaussian key distribution is inert; sampling silently uses ternary keys regardless of the preset params.rs:139-146 · client.rs:100-101,138-139

code REALISTIC_PARAMS declares KeyDist::Gaussian with key_sigma_* = Some(1.0) (placeholder, not the paper σ's) and a stray 26 that lands in the unused key_bound_2 slot.8 But key_dist_*/key_sigma_*/error_sigma are never read to build a distribution — Client::setup takes the Distribution as a separate argument, and every call site passes Ternary.9 So the preset's security/noise story is decorative. This is the implementation face of reviewer issue #2 — the \(\mathbb E[s_i^2]\) factor the paper's CMux/DMux lemmas omit, now a confirmed correctness bug in its own right (A9).10 The twist that finding exposes: the inert preset is a lucky bug here: the ternary keys it silently falls back to are precisely what keeps the noise budget closeable, where the paper's intended Gaussian \(\sigma{=}32\) key would break it.

Confidence: high on inertness (grep-verified); the proof-soundness link to issue #2 is the reviewers' analysis, reported as such. Fix: drive sampling from PIRParams (single source of truth) and populate real σ's, or delete the dead fields.

mediumA5 — Decode threshold divergence: code uses \(q_4/p\) (Yue-correct); the paper's Appendix C budget is written against \((q_3-q_4)/p\) rlwe.rs:188-221,297-308 · paper p.27

code decrypt_asymmetric rescales \(A'\!\cdot\!S\) from \(q_3\) to \(q_4\) and decodes at modulus \(q_4\), giving an effective margin \(\Delta/2 = (q_4/p)/2 = 256/2 = 128\).11 paper Appendix C states the correctness condition \(\lVert E_{\text{final}}\rVert_\infty \le \lfloor(q_3-q_4)/p\rceil/2-1 \approx 2.6\times10^5\).12 unverified Reviewer Yue Chen argues the threshold must be \(q_4\)-based (as the code does), making the paper's stated budget ~2000× too generous;13 the code is the conservative/likely-correct one, but it means the paper's proof does not describe the code's actual margin, and whether the small-ring noise really stays below 128 at paper σ is untested (see A3).

Confidence: high that code and paper text disagree (decode-at-\(q_4\), \(\Delta/2{=}128\), and the \(\approx2.6\times10^5\) / \(\approx2000\times\) arithmetic all re-verified); the "Yue is right" judgment is reported on his authority. Fix: reconcile the paper erratum with the code's decode and add a noise-vs-128 assertion.

lowA6 — VIA (non-C) \(q_1\) is two distinct primes in code vs a prime-squared in the paper rns/basis.rs:309 (ViaQ1Rns) · paper App. B, p.22

paper Appendix B (p.22) prints VIA \(q_1 = 268369921^2\) (a prime square). code uses two distinct NTT-friendly primes \(268369921\cdot536608769\), also \(\approx 2^{57}\).14 inference A true prime-square is not square-free and cannot be CRT-split into distinct RNS channels, so the two-prime substitution is a deliberate implementability choice, not a bug. Same magnitude; affects only the unimplemented VIA variant: VIA-C's \(q_1\) primes match the paper exactly.

Confidence: high (read at source; both values directly observable in App. B). Cosmetic unless VIA is implemented.

mediumA7 — Ciphertext wire serialization is unimplemented; communication-size claims cannot be measured from the code wire/format.rs:99-101,167-172

code Only a Vec<u64> placeholder codec exists; the WireFormat impls for CompressedQuery/CompressedAnswer are absent and PrgCompressed::serialize is todo!() (the deserialize / mask-regeneration side is implemented, but the byte-emitting path is not).15 The e2e tests pass objects in-memory, and no size accounting exists anywhere in the tree. VIA's headline metric is communication size, so this is a meaningful coverage gap for the value proposition.

Confidence: high. Fix: implement and size-test the wire format; gate on byte counts vs Table 4.

refutedA8 — Two suspected issues do not hold in this port modulus.rs:454,467 · rlwe.rs:198-200

code (a) Plaintext modulus is correct: ViaCP = 16 everywhere (ViaP = 256 is the separate, correct VIA value); no leftover MODULUS_PC = 256 exists: the constant the authors discussed (May 11) lives in their own C++ owniai/VIA, not in this port.16 (b) Constant-time decode: the secret-key centring on the decode path uses the constant-time to_centered_coeffs_ct; the non-CT helper is confined to public/revealed values.17

Confidence: high (read at source).

highA9 — The paper's DMux/CMux noise bound omits the secret \(\mathbb E[s^2]\) factor, so its intended Gaussian-key parameters fail \(2^{-40}\) (Yue's bug, now confirmed in-repo) dmux_noise_empirical.rs · via-estimator/src/lib.rs · paper Lemmas C.1/C.2, p.24 · issue #3

paper The DMux/CMux external-product noise bound (Lemmas C.1/C.2) charges the approximate-decomposition residual as \(\sim n\,q^2/B^{2\ell}\) — with no secret-key factor — yet the paper's own conversion (C.3) and ring-switch ([45]) lemmas do carry an \(\mathbb E[s^2]\) factor on the same kind of term. Yue flagged this internal inconsistency (issue #3): the bound holds only for a small/binary secret and is too aggressive for the paper's intended Gaussian \(\sigma{=}32\) key.

code We settled it both ways. Empirically (dmux_noise_empirical): a real DMux at \(n_1{=}4096\), swept over secrets, shows the residual scales as \(\mathbb E[s^2]\) to ~1%: the \(\sigma{=}32\) secret carries 1519× the ternary noise and exceeds the paper's own \(\times1\) budget by ~1000×. Analytically (via-estimator, toggle yue_residual_correction): with the factor restored, the paper's Gaussian design fails \(2^{-40}\) even with erratum bases (test yue_correction_breaks_paper_gaussian). inference Consequence, and the reason A4 matters: via-rs runs ternary keys (\(\mathbb E[s^2]{=}\tfrac23<1\)), which shrink the residual: so the substitution that weakens security is exactly what keeps correctness closeable.

Confidence: high — empirical (\(\pm\)~1%) and analytic agreement, both CI-gated. This is a paper/scheme correctness finding (the bound, not via-rs code per se); it was previously buried in this page's open questions and is promoted here. Fix (for any Gaussian-key instantiation): re-derive the CMux/DMux bound with the \(\mathbb E[s^2]\) factor and re-select parameters; for via-rs's ternary SECURE_PARAMS, see the thin-margin caveat on Params · Concrete.

VIA-B (batch)

The findings above cover VIA-C at commit 9575286. This section covers the VIA-B batch variant merged later (upstream PR #10), and its source links are pinned to commit 62fe493. Same epistemic tags as above (paper / code / inference / unverified). Method: a fresh research + adversarial-review pass over the new code against paper §4.5–4.7 (Fig 9) and Appendix C.

What VIA-B adds, and how it answers a batch

code VIA-B is a thin batch shell over the VIA-C stack plus one new primitive layer, homomorphic repacking (the paper's §4.6; "Layer 7" in the code's own module numbering), all behind the via-b cargo feature (repack also needs alloc: the recursion holds a runtime Vec). The server answers T queries by running the VIA-C prefix (Fig 9 steps 1–6) once per query at the record-ring degree n3, repacking the T results into a single ciphertext (the one new step), then running response compression once, so T records cost roughly one answer.

flowchart TD
  Q["client: batch_query yields T compressed VIA-C queries"]
  Q --> AC["server: answer_through_crot x T  (Fig 9 steps 1-6, at record degree n3)"]
  AC --> RP["server: Repack to n2  (step 7) - recursive MLWEs-to-RLWE, depth log2(T n1 / n2)"]
  RP --> RC["server: RespComp x 1  (step 8)"]
  RC --> RV["client: recover then deinterleave_batch yields T records"]
  CK["query-compression cascade keys (at q1)"] -. borrowed, mod-switched to q2, no new offline payload .-> RP
  classDef s fill:#eaf2fb,stroke:#2b5dd1;
  classDef c fill:#e8f7ee,stroke:#1f9d6b;
  class AC,RP,RC s;
  class Q,RV c;
            

code Repack (repack.rs, Layer 7) realizes the paper's MLWEs-to-RLWE conversion: extract each input to an MLWE, then recursively pair-convert (mlwes_to_mlwe, d=2) over \(\log_2(T\,n_1/n_2)\) levels into one RLWE, reusing the VIA-C conversion cascade's own key-switch step (conv_step) and borrowing the query-compression cascade keys, so repacking adds no new public parameters (paper §4.6 Remark). The client's deinterleave_batch is a pure strided permutation that inverts the repack interleave. Construction verdict: code faithful to Fig 9 / §4.6 for the single-repack case; the paper's vectorization path (\(T > n_1/n_3\)) is not implemented (see VB-6).

Findings (VIA-B)

critical VB-1 — Production VIA-B correctness is never end-to-end tested integration/batch_e2e_paper.rs · primitives/repack.rs

code The toy batch round-trip passes (I ran it: via_b_toy_batch_roundtrip + …covers_cells_and_slots, 2/2), but at ViaBToyParams (n2=16), ternary keys, a 2×2 database. The production configuration (T=256, n3=2, the paper's Gaussian σ, real DB dimensions) has no end-to-end correctness test: the paper-scale batch e2e runs T=8 / n3=64 (the record-fit boundary; "T=256 ≈ 3 h"), ternary keys, 2×2 DB, and is #[ignore]d; the T=256 path exists only as #[ignore]d repack "spike" tests on fresh-encrypted inputs (not the noise-laden answer pipeline). inference The toy/T=8 tests cannot exercise the production noise regime: half the repack depth, ternary keys instead of the paper σ, and no accumulated first-dimension/CMux noise. So production VIA-B correctness is asserted structurally, not verified: the same gap as VIA-C (A3), compounded by the deeper repack.

Confidence: high. Fix: a paper-noise, production-dimension batch correctness test (at least one size), plus an analytic θrep/θans budget.

high VB-2 — VIA-B inherits VIA-C's draft gadget bases, so the security/noise drift carries over protocol/presets.rs · HackMD erratum

code ViaBRealisticParams / REALISTIC_B_PARAMS reuse the VIA-C draft Table-6 bases (DMux 55879, CMux 81, ring-switch 8, conv ℓ=18), not the authors' erratum (18073 / 307 / 4 / 11). Because VIA-B's repack and prefix run on the same rings \(R_{n_1,q_1}\) / \(R_{n_2,q_2}\), the VIA-C findings carry over verbatim: the security drift (paper-claimed 110 → reviewers' measured ~72–88 bits, A1/A2) and the tight noise budget apply to VIA-B too, and the in-repo \(P_{\text{fail}}\) calc now proves the draft bases miss \(2^{-40}\) (A1), with the \(\mathbb E[s^2]\) bound bug (A9) applying to VIA-B's DMux/CMux identically. inference Crucially, there is no SECURE_B_PARAMS analogue of the \(\ge120\)-bit VIA-C fix: so VIA-B ships no certified-secure, certified-correct preset at all. code Clean by contrast: p=16, n3=2, T=256 match the paper, and the legacy p=256 bug is not inherited.

Confidence: high.

medium VB-3 — The paper's repack-noise formula undercounts the implemented depth at the production batch size primitives/repack.rs · paper Appendix C, step 7

code The repack recursion is \(\log_2(T\,n_1/n_2)\) levels deep: 10 for the production T=256 preset (steps keys_4 … keys_2048), each adding \(2\theta_{ks}\). This faithfully matches the paper's construction (recurse over the padded count \(d n/k = T\,n_1/n_2\)). paper But Appendix C's noise formula writes \(\theta_{rep} = \theta_{crot} + 2\theta_{ks}\log n_2\) (=9 at \(n_2=512\)), which equals the true depth only when \(T n_1/n_2 = n_2\) (T=128). inference At the headline T=256 the formula undercounts by one \(2\theta_{ks}\) level (10 vs 9). In magnitude that is ~11% of the repack key-switch term \(2\theta_{ks}\log n_2\), and a smaller fraction of \(\theta_{rep}\) overall, which is dominated by \(\theta_{crot}\). So the code is right to the construction; the Appendix-C \(\theta_{rep}\) is the optimistic side, but the practical shortfall is modest.

Confidence: high on the divergence (depth 10 vs formula's 9, re-verified arithmetically); the materiality is small and the "~11%" applies to the key-switch term only.

medium VB-4 — Repack noise omits the key mod-switch and approximate-gadget terms; the §(3) S² concern lands upstream primitives/repack.rs · primitives/gadget.rs · HackMD Yue §(3)

code The borrowed cascade keys ship at \(q_1\) and are mod-switched to \(q_2\) inside repack; that rounding noise is not in the \(\theta_{rep}\) bound. Repack also reuses the scheme's approximate gadget decomposition (reconstruction error \(\approx \mathrm{round}(q/B^\ell)/2\)), which the simple \(\theta' \le \theta_c + 2\theta_{ks}\) bound omits. unverified Reviewer Yue Chen's §(3) "the message should be \(S^2\)" concern targets the RLWE→RGSW step in query expansion (which VIA-B inherits from VIA-C, since repack borrows those very keys), and is explicitly hedged/open: it is not a settled undercount of the repack's own key-switches (those are the Lemma-4.1 key-switching bound). The in-repo via-estimator noise calculator now models the VIA-C recursion, but not VIA-B's repack chain (\(\theta_{rep}\)), so these specific terms remain unquantified in-repo.

Confidence: high that the terms are omitted from the in-code bound; the magnitude is unquantified (the estimator does not yet cover repack).

medium VB-5 — The headline response size (1.81 KB, 127×) is not measurable from the code protocol/wire/format.rs

paper VIA-B's headline is a ~1.81 KB response for a 1 GB database with 256 batched queries (127× smaller than prior batch PIR; both numbers confirmed in Table 2 / §5.3). code But the compact wire serializer (PrgCompressed::serialize) is still todo!() and there is no ciphertext-level codec, so the response-size claim cannot be measured here, only inferred from the answer's structural shape (one RespComp ciphertext at \(n_2=512\)). Carry-over of VIA-C finding A7.

Confidence: high.

low VB-6 — The single-repack invariant is stricter than the paper; vectorization is unimplemented (as the paper itself leaves it) protocol/presets.rs · server/batch.rs

code A compile-time invariant T·N3 ≤ N2 ("single-repack record-fit") caps VIA-B at one repacked output ciphertext. inference That is stricter than the per-output-ciphertext packing capacity \(T \le n_1/n_3\); note this bound is not stated verbatim in the paper: the paper only says vectorization is needed for larger batches (and declines to detail it, citing Respire). The operative packing factor here is the ring-switch ratio \(D = n_1/n_2 = 4\). paper The Respire-style vectorization for the multi-output case (\(T > n_1/n_3\)) is not implemented: a faithful (more conservative) scope cut, not a divergence. Production T=256 sits exactly at the boundary \(T·N3 = N2 = 512\).

Confidence: high on the code invariant and the boundary arithmetic; the "\(T \le n_1/n_3\)" relation is inference, not a paper quote.

verified VB-7 / VB-8 — Two things VIA-B gets right primitives/repack.rs · client/batch.rs

code (VB-7) No new public parameters. Repack borrows a zero-copy suffix of the LWE→RLWE conversion cascade key — a byte-identity test asserts the borrowed keys equal a dedicated oracle — and for the production cross-type case (RNS \(q_1\) → single-prime \(q_2\)) it derives the \(q_2\) keys server-side from already-shipped material. No new client→server offline payload, matching paper §4.6 Remark. (VB-8) Constant-time. VIA-B adds no secret-dependent timing path: deinterleave_batch is a pure strided permutation on public dimensions, and repack runs on RLWE-uniform ciphertexts and key data with fixed-length gadget loops (as in the existing VIA-C gates).

Confidence: high (read at source; borrow proven by an in-repo byte-identity equality test).

VIA-B build & test

Open questions & uncertainties

Audit-of-audit

Every finding on this page (both the VIA-C findings and the VIA-B follow-up above) was independently re-checked by a separate adversarial pass whose remit was to disconfirm: four fresh reviewers re-read the primary sources — the paper, the VIA Security thread, and the code read at the same pinned commits (9575286 / 62fe493, via git show) — and tried to break each claim rather than confirm it. inference No finding was refuted. Every core claim held; the corrections were precision-level (a few line numbers, one page number, and one cross-finding \(\sigma\) mislabel), and they are folded into the findings themselves.

Re-audit (HEAD 6ddafdb). A later pass, after the parameterization work, revisited every finding against the new in-repo tooling. Net changes, folded in above: A9 is new (the \(\mathbb E[s^2]\) bound bug, promoted from an open question and now confirmed); A2 and A3 are partly resolved by the via-estimator crate (A3 downgraded high→medium: the analytic budget now exists; only an at-scale empirical witness is still missing); and A1/VB-2 are sharpened (the draft bases are now proven to miss \(2^{-40}\)). The A1–A8 source links stay pinned to 9575286; A9 and the tooling links pin to 6ddafdb.
Finding Verdict What the re-check changed
A1 gadget bases confirmed · corrected CMux base 81 is at :153, ring-switch 8 at :156 (not :152/:154); Table 6 is on p.23; conversion-key base 1811 distinguished from length \(\ell{=}18\) (unchanged)
A2 security_param confirmed · partly resolved u32, read only in asserts/Debug; 128 exceeds even the paper's own 110. Now cross-checked by via-estimator (~77 bits on the shipped ternary keys); residual defect is that the constant is still hand-typed, not derived
A3 no paper-noise test confirmed · downgraded to medium lines exact; the cited \(\sigma_{1,S}{=}32,\sigma_{1,E}{=}1024,\sigma{=}26\) are the genuine VIA-C distributions. Analytic \(P_{\text{fail}}\) now in via-estimator; empirical paper-noise test still absent
A4 inert Gaussian key confirmed · clarified inertness grep-verified; Yue's \(\sigma{=}4960\) is the plain-VIA figure: VIA-C keys are \(\sigma_{1,S}{=}32\) / \(\sigma{=}26\) (see fn 10)
A5 decode threshold confirmed decode at \(q_4\), \(\Delta/2{=}128\); paper budget \(\approx 2.6\times10^5\); ratio \(\approx 2000\times\) checks out
A6 VIA \(q_1\) confirmed · upgraded directly observable (App B prints \(268369921^2\)), not mere inference; a prime-square cannot be RNS-split, so two primes is deliberate
A7 wire serialization confirmed only a Vec<u64> codec; serialize is todo!(); no size accounting anywhere
A8 refuted concerns confirmed (both hold) ViaCP=16, no MODULUS_PC (the bug was in the authors' C++ owniai/VIA); decode centring is constant-time
A9 E[s²] bound bug new · confirmed promoted from open-question #2; empirical (1519× at σ=32) and analytic agreement, both CI-gated
VB-1 no production e2e confirmed only ignored T=8 e2e + ignored T=256 repack spike tests on fresh inputs
VB-2 inherited bases confirmed REALISTIC_B_PARAMS reuse the VIA-C draft bases on the same rings
VB-3 repack depth confirmed · softened depth 10 vs formula's 9 verified; "~11%" is of the key-switch term \(2\theta_{ks}\log n_2\), not of \(\theta_{rep}\) overall
VB-4 omitted terms confirmed key mod-switch + approximate-gadget terms omitted; Yue \(S^2\) concern is hedged/upstream
VB-5 response size confirmed 1.81 KB / 127× headline confirmed in paper; not measurable from code
VB-6 single-repack bound confirmed · re-tagged invariant + boundary arithmetic verified; "\(T\le n_1/n_3\)" is inference, not paper-stated
VB-7/8 no new params; CT confirmed (both hold) zero-copy borrow proven by a byte-identity test; no secret-dependent timing path

Footnotes

  1. VIA Security review note (HackMD, evolving) — Yue et al. (Turan, Yue, Keewoo), "Issue Report", May 7: "for the big and small ring according to the paper's parameters, we got 110 bits of security, but for the implementation we achieved approximately 88 and 72 bits of security." (They reproduce the paper's 110 from the paper's parameters, and measure 88/72 from the implementation's parameters, via the OpenFHE estimator.)
  2. protocol/presets.rs:150 (DMux base 55879), :153 (CMux base 81), :156 (ring-switch base 8); conv length \(\ell=18\) is carried in the ViaCRealisticParams type alias (no separate runtime base field). Bases identical to paper Table 6 (App. B, p.23) as printed.
  3. VIA Security review note (HackMD, evolving) — VIA authors, "Response from the authors", May 11, §2 Corrected Gadget Parameters: VIA-C bases conv(\(\ell{=}18,B{=}11\)), dmux(\(2,18073\)), cmux/rot(\(2,307\)), rs(\(8,4\)), giving \(\log_2 P_{\text{fail}}\approx-43.4\); "the gadget base values listed in Table 6 … were inadvertently left at draft values."
  4. protocol/params.rs (security_param: u32); at the pinned tree it was read only in the constructor, the Debug impl, and a display test, with no lattice/estimator code. An in-repo estimator (the via-estimator crate) has since been added; security_param is still a separate hard-coded constant rather than derived from it.
  5. Liu et al. (2025) (local: via-paper.pdf) §5.1, p.16: "110 bits of classical security … using the lattice estimator [46]."
  6. integration/client_server_e2e_paper.rs (NUM_ROWS=2,NUM_COLS=2), :69-71 (Distribution::Ternary), :146 (#[ignore]). Both ignored tests pass in release (verified, 35.7s). The σ's are the paper's VIA-C values (§5.1, p.16): \(\sigma_{1,S}{=}32,\ \sigma_{1,E}{=}1024\) on the big ring and \(\sigma{=}26\) on the small ring (the paper prints the small-ring σ under a typo'd \(\sigma_{1,E}\) subscript).
  7. No Appendix-C noise recursion in code (grep for \(P_{\text{fail}}\)/noise-recursion returns only doc-comment prose); criterion bench dirs are all toy_* (pipeline_toy default, pipeline_paper opt-in timing only).
  8. protocol/params.rs (arg order: …key_dist_2, key_bound_2, key_sigma_1, key_sigma_2, error_sigma, security_param); protocol/presets.rs supplies Gaussian,Gaussian,26,Some(1.0),Some(1.0),Some(1.0),128.
  9. grep: key_sigma_*/error_sigma/key_dist_*/key_bound_2 read only inside PIRParams::new asserts; client/client.rs,138-139 takes key_dist_1/2: Distribution as separate args; all test call sites pass Distribution::Ternary.
  10. VIA Security review note (HackMD, evolving) — Yue Chen, "Observations", May 31, §(2) CMux/DMux problem: TFHE assumes a binary key, so the term \(nq^2/(12B^{2\ell})\) "should now be updated to \(n\mathbb E[s_i^2]q^2/(12B^{2\ell})\)." The \(\sigma=4960\) Yue pairs with this is the plain-VIA small-ring key σ (the \(p=256\) instantiation); the implemented variant is VIA-C, whose keys are \(\sigma_{1,S}=32\) on the big ring (where DMux/CRot live) and \(\sigma=26\) on the small ring (where CMux lives): so for VIA-C the missing \(\mathbb E[s_i^2]\) factor would use \(\approx 1024\) / \(\approx 676\), not \(4960^2\). The structural point — non-binary key ⇒ a missing variance factor in Lemma C.1/C.2 — holds regardless. Cross-ref Liu et al. (2025) (local: via-paper.pdf) Lemma C.1/C.2, p.24-25.
  11. primitives/rlwe.rs (rescale (*v*q4+q3_half)/q3, then decode at q4) and :297-308 (decode uses q = modulus_value(scaled) = q4). Δ = q4/p = 4096/16 = 256, so Δ/2 = 128.
  12. Liu et al. (2025) (local: via-paper.pdf) Appendix C.2, p.25-27: the per-step variance recursion (θctrl→θdmux→θms→θfirst→θcmux→θcrot→θrep→θans) and condition \(\lVert E_{\text{final}}\rVert_\infty\le\lfloor(q_3-q_4)/p\rceil/2-1\) (p.27). With q3=8380417, q4=4096, p=16 this is \(\approx 2.6\times10^5\).
  13. VIA Security review note (HackMD, evolving) — Yue Chen, "Observations", May 31, §(1) Decryption error: the threshold "should only be correct when the infinite norm of the final error is \(\le (q_4/p)/2-1\), or just \(<\Delta/2\)," citing SpiralPIR Thm 2.11 and SimplePIR Thm C.1. (His worked bit-budget intuition uses the plain-VIA numbers — q4 15-bit, p=256 — but the formula critique applies to VIA-C's q4=4096/p=16 too.) Ratio \(2.6\times10^5/128\approx2000\).
  14. primitives/basis.rsViaQ1Rns = ConstRnsBasis<268369921, 536608769> (two distinct primes, product ≈ 2^57), vs paper App. B (p.22) "VIA \(q_1 = 268369921 \cdot 268369921\)"; :315 ViaCQ1Rns = <137438822401, 274810798081> matches paper VIA-C exactly. ConstRnsBasis asserts the two moduli are distinct and coprime, so it cannot represent a true prime-square. Verified at source.
  15. protocol/format.rs (the only two WireFormat impls are both for Vec<u64>), :167-172 (PrgCompressed::serialize is todo!(); its deserialize / regenerate_masks side is implemented). No WireFormat for CompressedQuery/CompressedAnswer; no byte-size accounting anywhere.
  16. primitives/modulus.rs (ViaP = PowerOfTwoModulus<8> = 256, the VIA value), :467 (ViaCP = PowerOfTwoModulus<4> = 16); protocol/presets.rs (p=16); grep over the pinned tree finds no MODULUS_PC: the MODULUS_PC=256 bug the authors discussed (May 11) was in their own C++ owniai/VIA, not in this port (nor in the clean via-spec Python lineage it descends from).
  17. primitives/rlwe.rs — secret centring via to_centered_coeffs_ct (the constant-time companion to the non-CT to_centered_i64 at primitives/modulus.rs, which is confined to sampling/lift/public-value paths).
  18. protocol/presets.rs and many provenance comments (e.g. client.py:117, server.py:196, server/resp_comp.rs) reference a Python reference; find … *.py over the tree returns only a CI script — the Python source is not in this checkout.