Audit — VIA-C & VIA-B correctness & security
Summary
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. 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.
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.
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.
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 re-run a noise estimate); add a comment distinguishing "Table 6 as printed" from "Table 6 corrected."
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.
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.
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 paper's
TFHE-derived CMux/DMux noise lemmas (C.1/C.2) assume a binary
key and omit the \(\mathbb E[s_i^2]\) factor; the code neither
uses the paper's Gaussian key nor models that factor.10
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.
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.
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.
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.
code
(a) Plaintext modulus is correct:
ViaCP = 16 everywhere (ViaP = 256 is
the separate, correct VIA value); no leftover
MODULUS_PC = 256 exists — the Python-reference bug
the authors noted is not present 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).
Audit-of-audit — adversarial validation
Every finding on this page (the VIA-C findings above and the
VIA-B follow-up below) 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.
| 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
18→11 distinguished
from length \(\ell{=}18\) (unchanged)
|
| A2 security_param | confirmed |
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)
|
| A3 no paper-noise test | confirmed |
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 Python reference); decode centring
is constant-time
|
| 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 |
Open questions & uncertainties
-
Does the code actually achieve \(2^{-40}\)
correctness?
Now computed analytically (
via-estimator::noise, with Yue's \(\mathbb E[s^2]\) residual correction): the paper's intended Gaussian-key design does not (the DMux/CMux bound is too aggressive for a large-variance secret; confirmed empirically — a measured DMux at n4096 (dmux_noise_empirical) shows the residual scales as \(\mathbb E[s^2]\) to ~1%, so the \(\sigma{=}32\) design carries \(1519\times\) the ternary noise), but via-rs's ternarySECURE_PARAMSclears \(2^{-40}\) on a thin, model-sensitive margin — an optional DMux \(\ell\!:\!2\to3\) bump widens it (see Fix). Still open: an empirical paper-noise/paper-dimension test (the analytic budget is no longer the gap). -
Real security level? No longer a missing
artifact: the in-repo
via-estimatorreports ~77 bits (ternary, binding small ring) for the published set and ≥156 forSECURE_PARAMS; the external reviewers' OpenFHE 72–88 figures (on C++ owniai/VIA) remain on their authority. Full reconciliation on Params · Concrete. -
Three-way paper↔Python↔Rust drift: the Rust
cites a Python reference (
client.py,server.py,resp_comp.py) that is not in this checkout, so only paper↔Rust drift is checkable here.18 - Reviewer proof issues #2/#3 (\(\mathbb E[s_i^2]\) term in CMux/DMux noise; \(S^2\) message in RLWE→RGSW) are paper-proof soundness questions; the code sidesteps them only because it runs ternary keys and models no noise — they would bite if Gaussian keys were wired (A4). Note the \(\sigma=4960\) those discussions cite is the plain-VIA figure; the VIA-C keys are \(\sigma_{1,S}{=}32\) / \(\sigma{=}26\) (fn 10).
-
Plain VIA is still not implemented.
VIA-B (batch) has since been implemented
(PR #10) behind the
via-bfeature — its toy batch round-trip passes — and is covered by the follow-up below.19
VIA-B (batch) — follow-up audit
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)
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.
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.
code Clean by contrast:
p=16, n3=2, T=256 match
the paper, and the legacy p=256 bug is not
inherited.
Confidence: high.
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.
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). No in-repo estimator exists to quantify any of this.
Confidence: high that the terms are omitted from the in-code bound; the magnitude is unquantified (no noise model).
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.
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.
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
- code Ran the toy batch suite:
via_b_toy_batch_roundtrip+via_b_toy_batch_covers_cells_and_slots— 2/2 pass (cargo test -p via-integration --features via-b;ViaBToyParams, ternary keys, 2×2 DB). - code The 4×8-grid and paper-scale (T=8 / n3=64) batch e2e tests exist but are
#[ignore]d (ternary keys, 2×2 DB). - unverified The production T=256 / n3=2 path has only
#[ignore]d repack "spike" tests on fresh-encrypted inputs — no full-pipeline correctness e2e (VB-1).
Footnotes
- 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.) ↩ ↩
-
protocol/presets.rs:150 (DMux base 55879), :153 (CMux base 81), :156
(ring-switch base 8); conv length \(\ell=18\) is carried in
the
ViaCRealisticParamstype alias (no separate runtime base field). Bases identical to paper Table 6 (App. B, p.23) as printed. ↩ - 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." ↩
-
protocol/params.rs
(
security_param: u32); at the pinned tree it was read only in the constructor, theDebugimpl, and a display test, with no lattice/estimator code. An in-repo estimator (thevia-estimatorcrate) has since been added;security_paramis still a separate hard-coded constant rather than derived from it. ↩ - Liu et al. (2025) (local: via-paper.pdf) §5.1, p.16 — "110 bits of classical security … using the lattice estimator [46]." ↩
-
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). ↩ -
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). ↩ - 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. ↩
-
grep:
key_sigma_*/error_sigma/key_dist_*/key_bound_2read only insidePIRParams::newasserts; client/client.rs,138-139 takeskey_dist_1/2: Distributionas separate args; all test call sites passDistribution::Ternary. ↩ - 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. ↩
-
primitives/rlwe.rs
(rescale
(*v*q4+q3_half)/q3, thendecodeat q4) and :297-308 (decodeusesq = modulus_value(scaled)= q4). Δ = q4/p = 4096/16 = 256, so Δ/2 = 128. ↩ - 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\). ↩
- 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\). ↩
-
primitives/basis.rs
—
ViaQ1Rns = ConstRnsBasis<268369921, 536608769>(two distinct primes, product ≈ 2^57), vs paper App. B (p.22) "VIA \(q_1 = 268369921 \cdot 268369921\)"; :315ViaCQ1Rns = <137438822401, 274810798081>matches paper VIA-C exactly.ConstRnsBasisasserts the two moduli are distinct and coprime, so it cannot represent a true prime-square. Verified at source. ↩ -
protocol/format.rs
(the only two
WireFormatimpls are both forVec<u64>), :167-172 (PrgCompressed::serializeistodo!(); its deserialize /regenerate_masksside is implemented). NoWireFormatforCompressedQuery/CompressedAnswer; no byte-size accounting anywhere. ↩ -
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 noMODULUS_PC— theMODULUS_PC=256bug the authors flagged (May 11) was in the Python reference, not this port. ↩ -
primitives/rlwe.rs
— secret centring via
to_centered_coeffs_ct(the constant-time companion to the non-CTto_centered_i64at primitives/modulus.rs, which is confined to sampling/lift/public-value paths). ↩ -
protocol/presets.rs
and many provenance comments (e.g.
client.py:117,server.py:196,server/resp_comp.rs) reference a Python reference;find … *.pyover the tree returns only a CI script — the Python source is not in this checkout. ↩ -
grep over crates/{client,server,protocol} at
9575286: pipeline monomorphised againstViaCPublicParams; no Figure-4 path, norepack/via_b/MLWEs→RLWE. VIA-B repacking was subsequently merged in PR #10 (62fe493) and is covered by the follow-up above. ↩