Audit
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. 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.
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.
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.
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
\(\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.
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 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).
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)
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, 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.
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). 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).
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).
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). -
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 issue #3 (the \(S^2\) message in RLWE→RGSW) remains a paper-proof soundness question that the code sidesteps by running ternary keys; it would bite if Gaussian keys were wired (A4).
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.
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
18→11 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
- 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 discussed (May 11) was in their own C++owniai/VIA, not in this port (nor in the cleanvia-specPython lineage it descends from). ↩ -
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. ↩