Security & Status¶
PyFE4AI is a research prototype: no scheme is hardened against side channels, and the default parameters are toy values. This page lists the review status of every scheme and the parameter presets; the README sections Scheme Status, Security Profiles and Known Issues / Security Notice add measured costs and the remaining limitations.
Scheme status¶
42 registered schemes: 34 reviewed, 5
experimental, 3 unreviewed and 0
known-insecure. The experimental ones are the threshold layers of tMIFE-LWE,
tMCFE-LWE, tMCFE-Ring-LWE and tMCFE-FH-Multi-IPE and the carry mask of
dMCFE-DDH: our own constructions on top of published schemes, with no
published security proof. Query a scheme at runtime with
pyfe4ai.get_scheme_status(family, variant) (or "family/variant") or
FESchemeWrapper(...).status;
the key generator and crypto objects of a known-insecure scheme emit
FESecurityWarning. The table is rendered
from SCHEME_STATUS, which is derived from the
scheme registry (pyfe4ai.core.registry); the status and fidelity
values are defined with SchemeStatus.
Scheme |
Status |
Fidelity |
Construction |
Notes |
|---|---|---|---|---|
reviewed |
faithful |
ABDP15 Construction 1 (DDH) |
signed x, y; decryption bound dlog_bound (default 10^(precision + 2)) |
|
unreviewed |
unknown |
ABDP15 Construction 1 (DDH) in ristretto255 |
ristretto255 (RFC 9496, about 126-bit security: Pollard rho in a group of order 2^252) instead of a 3072-bit Z_p^* subgroup; group arithmetic in Rust (curve25519-dalek) with the native extension, else in pure Python and not constant-time; new code, not yet reviewed |
|
reviewed |
adapted |
ABDP15 full version (ePrint 2015/017), LWE |
the LWE instantiation as revised in the full version (no r-ary decomposition); its selective IND-CPA proof is the full version’s Thm. 4.4 with Thms. 6.6 and 6.7 (Bourse 2017 Thm. 4.3.5 with 8.2.2, 8.2.3, 8.3.2), not PKC Thm. 2, which does not cover noisy LWE keys; it reduces to LWE with errors sigma / (1 + 2X sqrt(eta)), the width standard reads the 128-bit table at; signed X/Y-bounded inputs with centred decoding; GoFE parameter recipe; pk noise E <- D_{Z,sigma_q} exactly (FACCT) under standard, the library-wide sampler under toy; A expanded from a public seed (SHAKE-128) |
|
reviewed |
faithful |
ALS16 (DCR) |
D_{Z,sigma} realised as a high-precision rounded Gaussian |
|
reviewed |
faithful |
ALS16 DDH (ACFGU18 Fig. 7, k = 1) |
h = g^a with a discarded |
|
reviewed |
adapted |
BMMS21 Sec. 4 (selective) + Remark 1 batching |
signed messages and weights (p = 2lXY + 2, centred decoding); widths from the Sec. 4.2 constraints (the paper’s Table 1 misses its smoothing conditions); one ciphertext packs up to ring_n vectors; single NTT prime q; ring_n defaults to the toy value 32 |
|
reviewed |
adapted |
BMMS21 Sec. 5 (adaptive) |
m >= 5 key polynomials instead of m = 3, which admits no modulus under the paper’s App. C.1 constraints (sigma’ >= q^(2/m) from Ring-LHL); signed inputs (p = 2lXY + 2, leveraging over (2X+1)^(2l)); one vector per ciphertext. Experimental: ndarray_layout = “packed” (up to ring_n vectors per ciphertext, leveraging over the span of the differences) rests on this project’s own argument, independently checked, not externally reviewed |
|
reviewed |
adapted |
ALS16 LWE (ACFGU18 Fig. 8) |
signed inputs (K = 2 eta X Y + 1, centred decoding); GoFE parameter recipe with m = 4 n log2 q (ALS16 Theorem 2); D_{Z,sigma} realised as a rounded Gaussian |
|
reviewed |
adapted |
ABDP15 Construction 1, variable length |
vectors of length <= eta handled as zero padding (prefix keys, truncated ciphertexts) |
|
reviewed |
adapted |
KLMMRW18 Sec. 3 |
vectors padded to (x, 1, 0) / (y, 0, 1), so eta = 1 and zero vectors are safe; keys in G1, ciphertexts in G2; generic bilinear group model; the encryption key is master-secret equivalent |
|
reviewed |
adapted |
Gay20 Fig. 8 (CPA, k = 1) |
M is a random full-rank public matrix (subspace_dim < eta, default 1), published with V^T M in the clear; keys leak M^T y, which for small eta - subspace_dim often determines a bounded y; public Enc needs bounded t; Enc’ is run by the key generator; no QANIZK |
|
reviewed |
adapted |
ACFGU18 Fig. 4 + ABDP15 (DDH) |
ACFGU18 instantiates Fig. 4 with ALS16; here the selectively secure ABDP15 IPFE in every slot |
|
unreviewed |
unknown |
ACFGU18 Fig. 4 + ABDP15 (DDH) in ristretto255 |
ristretto255 (RFC 9496, about 126-bit security: Pollard rho in a group of order 2^252) instead of a 3072-bit Z_p^* subgroup; group arithmetic in Rust (curve25519-dalek) with the native extension, else in pure Python and not constant-time; new code, not yet reviewed |
|
reviewed |
adapted |
ACFGU18 Fig. 4 + ABDP15 (LWE) |
ACFGU18 instantiates Fig. 4 with ALS16; here the selectively secure ABDP15 IPFE (same two-step decryption; full-version proof, see sife/lwe), with parameters for dimension n * eta (footnote 14); the slot challenges of the ACFGU18 reduction differ by up to 4X, so standard reads the 128-bit table at sigma / (1 + 4X sqrt(eta)); slots share A, expanded from a public seed (SHAKE-128); pk noise exact (FACCT) under standard |
|
reviewed |
adapted |
ACFGU18 Fig. 4 + ALS16 (DCR, Fig. 9) |
slots share N and g; D_{Z,sigma} realised as a high-precision rounded Gaussian |
|
reviewed |
adapted |
ACFGU18 Fig. 4 + ALS16 (DDH, Fig. 7) |
slots share the group and h (the matrix A of Fig. 7) |
|
reviewed |
adapted |
BMMS21 Sec. 6 MIFE-compiler (ACFGU18) |
slots share a; parameters sized for dimension n * eta, with the Sec. 4.2 widths for bound 3X (ACFGU18 Fig. 4, footnote 12) |
|
reviewed |
adapted |
ACFGU18 Fig. 4 + ALS16 (LWE, Fig. 8) |
slots share A; parameters derived for dimension n * eta and bound 3X (ACFGU18 footnote 14), m = 4 n log2 q |
|
reviewed |
adapted |
ACFGU18 Fig. 12 (k = 1) |
one r per key shared by all slots; per-slot FH-IPFE as in mcfe/fh_ipe (LV16 padding of App. B); asymmetric pairing (default BLS12-381); keys carry a random id, never a digest of y |
|
reviewed |
adapted |
DOT18 Sec. 3.1 (bounded, k-LIN, k = sec_level) |
n >= 2 enforced (zero sharing r_i); no Remark B.1 SKE layer, so hiding assumes every slot contributes a ciphertext; slot i’s client holds B^_i and can decode its own slot of a key; keys are group elements only, decryption does not need y |
|
reviewed |
adapted |
ACFGU18 Fig. 4 + ABDP15 + Shamir (TAPFed setting) |
the functional key (d_i, z) is Shamir-shared mod q; any t servers interpolate in the exponent (threshold-ElGamal style), as mcfe/ddh_threshold |
|
experimental |
ad-hoc |
MIFE-LWE + replicated / Shamir sharing + smudging |
MIFE layer as published; the threshold layer (statistical flooding, derandomised noise, enlarged q, clients’ HMAC tags on ciphertexts so that servers only decrypt ciphertexts made by the clients, replicated key sharing for t < s, where Shamir shares let partials reveal the decryption noise modulo small integers) is our own; the opt-in sharing=’replicated-seeded’ expands all key pieces but one from secret 256-bit seeds and hides the key shares only computationally (SHAKE-256 keyed by the seeds as a PRF); full replicated sharing stays the default for t < s; standard refuses it (at the reduction width of mife/lwe it needs the very end of the 128-bit table, 5888 to 6144, for a few small bounds and more for most others) |
|
reviewed |
faithful |
CDGPP18 |
||
unreviewed |
unknown |
CDGPP18 in ristretto255 |
ristretto255 (RFC 9496, about 126-bit security: Pollard rho in a group of order 2^252) instead of a 3072-bit Z_p^* subgroup; labels hashed with RFC 9380 hash_to_ristretto255; group arithmetic in Rust (curve25519-dalek) with the native extension, else in pure Python and not constant-time; new code, not yet reviewed |
|
reviewed |
adapted |
ABMPSW20 Fig. 4, selective parameters |
signed messages and weights (K = 2nXY + 1, centred decoding); t <- D_{Z,sigma_t} exactly (FACCT) by default, rounded selectable under toy |
|
reviewed |
faithful |
ABMPSW20 Fig. 3 |
D_{Z,sigma} realised as a high-precision rounded Gaussian |
|
reviewed |
faithful |
ABMPSW20 Fig. 2 (D_k-MDDH) |
k = mddh_k (default 1, where it equals CDGPP18) |
|
reviewed |
adapted |
BMMS21 Sec. 6 MCFE-compiler (identity-based) |
functional keys are bound to a label; ndarray values are packed into one ciphertext per chunk, each chunk with its own label pad; parameters as mife/ring_lwe (widths for bound 3X) |
|
reviewed |
adapted |
ABMPSW20 Fig. 4, adaptive parameters |
signed messages and weights (K = 2nXY + 1, centred decoding); t <- D_{Z,sigma_t} exactly (FACCT) by default, rounded selectable under toy; m0 grows with n log2(2X + 1) |
|
reviewed |
adapted |
AGT21b Sec. 6.2 (as recapped in NPS24 Sec. 2) |
FH-IPFE = ACFGU18 Fig. 12 (n = 1, SXDH) with LV16 padding; asymmetric pairing (default BLS12-381); keys carry a random id, never a digest of y |
|
experimental |
ad-hoc |
AGT21b FH-MCFE + Shamir |
FH-MCFE layer as published; the key exponents Shamir-shared in the exponent ([e^(k)]_2, [z^(k)]_T), partial decryptions in G_T and labelled, client-tagged ciphertexts are our own; FH-IPFE = ACFGU18 Fig. 12 (n = 1, SXDH) with LV16 padding; asymmetric pairing (default BLS12-381); keys carry a random id, never a digest of y |
|
reviewed |
adapted |
NPS24 Fig. 1 (selective FH-DMCFE) |
explicit tag-f, each client’s key depends on (tag-f, y_i) only and is derived deterministically; one key per client and tag-f (enforced per client object); FH-IPFE = ACFGU18 Fig. 12 (n = 1, SXDH) with LV16 padding; asymmetric pairing (default BLS12-381); keys carry a random id, never a digest of y |
|
reviewed |
adapted |
CDGPP18 + Shamir (TAPFed setting) |
the aggregated key is Shamir-shared; any t servers interpolate in the exponent (threshold-ElGamal style) |
|
experimental |
ad-hoc |
ABMPSW20 Fig. 14 (MCFE1 = CDGPP18) + carry mask |
Fig. 14 is stated for MCFEs without a discrete log in decryption; contributions are reduced mod q and masked by q rho_i (rho_i from a per-client key and H(y)) so that the carry of their sum stays hidden – our own argument; MCFE2 = ABMPSW20 Fig. 3 (DCR); the zero-sum MCFE2 keys (pairwise masks) are sampled in-process |
|
experimental |
ad-hoc |
ABMPSW20 Fig. 4 + replicated / Shamir sharing + flooding |
MCFE layer as published; the threshold layer (replicated key sharing for t < s, Shamir for t = s) and its LWE-based flooding argument are our own (see the module docstring); the opt-in sharing=’replicated-seeded’ expands all key pieces but one from secret 256-bit seeds and hides the key shares only computationally (SHAKE-256 keyed by the seeds as a PRF); full replicated sharing stays the default for t < s |
|
reviewed |
adapted |
ABMPSW20 Fig. 14 (MCFE1 = Fig. 4) |
MCFE2 = ABMPSW20 Fig. 3 (DCR); the zero-sum MCFE2 keys (pairwise masks) are sampled in-process |
|
experimental |
ad-hoc |
BMMS21 identity-based MCFE + replicated / Shamir sharing + smudging |
MCFE layer as published; the threshold layer (statistical flooding, derandomised noise, enlarged q, clients’ HMAC tags on ciphertexts, replicated key sharing for t < s, where Shamir shares let partials reveal the decryption noise modulo small integers) is our own; the opt-in sharing=’replicated-seeded’ expands all key pieces but one from secret 256-bit seeds and hides the key shares only computationally (SHAKE-256 keyed by the seeds as a PRF); full replicated sharing stays the default for t < s; by default binary ciphertexts (format 2: ct0 cut to the batch length and every value strictly below q, tags over the parameters’ digest and the bytes, binary partials and key shares), an RNS modulus (q a product of at least three NTT primes, each above s) and split key shares (sk_y once per weights, the label terms per round); ct_format=’json’, ring_modulus=’prime’ and key_shares=’full’ select the formats of earlier versions |
|
reviewed |
adapted |
BMMS21 Sec. 6 identity-based DMCFE (ABKW19 + GDSum) |
GDSum realised as pairwise PRF zero-sum masks (its full specification is only in the ePrint version); pairwise secrets sampled in-process |
|
reviewed |
adapted |
ABMPSW20 Fig. 14 (MCFE1 = Fig. 3) |
MCFE2 = ABMPSW20 Fig. 3 (DCR); the zero-sum MCFE2 keys (pairwise masks) are sampled in-process |
|
reviewed |
adapted |
Gay20 Fig. 4 over Fig. 8 (CPA) |
signed inputs (discrete log in [-n m B^3, n m B^3]); CPA variant (no QANIZK); asymmetric pairing (default BLS12-381) |
|
reviewed |
adapted |
DSGPP18 Fig. 2 |
public key pk = (g1^s, g2^t) as in the paper; signed inputs with one bound B for x, y and F (discrete log in [-n^2 B^3, n^2 B^3]); generic bilinear group model |
|
reviewed |
adapted |
AGT22 Sec. 5 (MIFE for quadratic functions) |
cross-user terms only (Def. 2.9); per-user encryption keys made of master ciphertexts; building blocks TAO20 FH-IPFE, Fig. 9 and Fig. 1 as in the paper; PRF = HMAC-SHA512; pos-security (every user contributes); k = mddh_k >= 2 |
Security profiles¶
The security_profile entry of a key generator’s config selects its
parameters: "toy" (the default) is fast and not secure;
"standard" aims at 128-bit classical security and refuses explicit
values below it. Its exceptions: the pairing-based schemes run on
BLS12-381, about 120-126-bit after the exTNFS attacks (with a
FESecurityWarning),
and sife/fullysec_lwe, mife/fullysec_lwe (ALS16),
mife/lwe_threshold and mcfe/paillier_decentralized are refused.
pyfe4ai.core.profiles below gives the parameters per family,
including matrix_mode for the ABDP15 LWE schemes; Configuration options
lists every option with its default under each profile, and the option
combinations that are refused.
For the ABDP15 LWE schemes (sife/lwe, mife/lwe) the 128 bits are
those of the LWE problem that their security proof reduces to. The
lattice-estimator table is read at the error width
sigma' = sigma / (1 + B sqrt(eta)) of that problem (B = 2 X, or
4 X per slot of mife/lwe), not at the wider sigma of the public
key. That makes the dimension 17 to 67 percent larger for
8 <= X = Y <= 1000, and up to about twice as large at X = Y = 1.
The proof is the ABDP15 full version (ePrint 2015/017, Oct. 2015), Thm. 4.4
with Thms. 6.6 and 6.7 (Construction 6.5, Sec. 6.2), written out in
F. Bourse’s PhD thesis (ENS 2017), Thm. 4.3.5 with Thms. 8.2.2, 8.2.3,
8.3.2. It is not Theorem 2 of the PKC 2015 paper, whose simulation does not
cover noisy LWE keys. The width sigma' is the condition derived in the
proof of Thm. 6.6 (= Bourse, Thm. 8.2.2); the full version’s Sec. 6.2
parameter list states the stronger, sufficient (l B + 1) sigma'.
Hypotheses of the papers that the library meets differently:
The literal
p > l B^2of Thm. 4.4 / Sec. 6.2 is not needed for the Regev instance. The change of basis acts on secret keys mod the LWE primeq. The library decodes the integer inner product (p > 2 eta X Y + 1), so admissible keys are orthogonal tox1 - x0overZ.The
4 Xper slot ofmife/lweis the library’s ACFGU18 composition, covered by neither text.The thesis’s LWE hardness bound (an absolute width above
2 sqrt(n); not stated in the full version) is met understandard:sigma' >= 2^16, the table’s smallest width.
mife/lwe_threshold is refused, like the ALS16 schemes. Once its modulus
is enlarged for flooding (stat_param = 128), it needs a dimension at the
very end of the table at that width (5888 to 6144, with a public matrix of
6.5 to 7.8 * 10^9 entries) for a few small bounds, e.g. X = Y in
{1, 2, 3, 8, 10} at eta = 1, and beyond it for most others (X = Y =
4 to 6, X = Y >= 12, most eta >= 2).
The opt-in KL-divergence accounting of the flooding noise
(pyfe4ai.schemes.threshold.kl) would bring it to about 4864 for
two clients, s = t = 3 and 2^40 flooded values. It applies only with
flooding_accounting = "kl", t = s and an explicit
max_partial_decryptions budget; the public matrix would still have
4.1 * 10^9 entries ("stream" mode), and the guarantee is weaker and
holds only for the first max_partial_decryptions partial decryptions of
every server: about stat_param - 6.85 bits in the bit-security sense of
Micciancio and Walter, a total statistical distance of about 2^-65 at
stat_param = 128. The refusal under standard holds with either
accounting; "kl" applies to mife/lwe_threshold under toy.
The arguments of the security reviews that are part of the documentation:
Threshold trust model¶
The decryption servers of the threshold schemes (tMIFE, tMCFE) are
honest-but-curious: fewer than t of them learn nothing beyond the result,
but a partial decryption carries no proof of correctness, so one deviating
server changes the result unnoticed. combine_decrypt accepts partial
decryptions for several enrolled sets and raises if they disagree (see
combine_consistently()); it also
raises (FESchemeError, for one value and
for an ndarray element alike) when the partial decryptions of one set were
computed for different ciphertexts. In
tMIFE-LWE, tMCFE-Ring-LWE and tMCFE-FH-Multi-IPE, servers only decrypt
ciphertexts carrying their clients’ MAC tags. With the binary ciphertexts of
tMCFE-Ring-LWE (ct_format="binary", its default; "json" selects the
format of earlier versions) the tags also cover the digest of the public
parameters, and the encoding is unique (values strictly below q), so that
the flooding noise, seeded with the ciphertexts’ bytes, cannot be redrawn by
re-encoding a ciphertext. Its key shares are split by default: a server keeps
its share of the label-independent part of the key once per weights and
receives the shares of the round’s label terms per round; a linear sharing
reused with fresh sharings of the label terms is a sharing of each round’s
key, the shares of t - 1 servers stay independent of the keys, and the
noise is seeded as for a whole key share (key_shares="full" issues whole
key shares). A server refuses a label part without the weight part of the
same weights and share set, and key shares and ciphertexts of another format
or other public parameters; a combiner refuses partial decryptions of another
format, and partial decryptions of different sharings of one key: every
sharing the key generator issues has a random sharing_id that the
partials carry, since partials of two sharings (a label shared again after it
left the key generator’s cache, LABEL_PARTS_KEPT) would decode to a wrong
value inside the decoding bound rather than fail. A second sharing reveals
nothing: one server’s answers under the two sharings differ by its share of
a sharing of zero, which t - 1 servers compute from their own parts.
Store and transmit the sharing_id with every key share and partial
decryption: partials without one (as from key shares of earlier versions)
combine only with each other, so a storage or transport layer that drops the
id on every side would let partials of two sharings combine to a wrong value
unnoticed.
Partial decryptions carry no digest of the public parameters, so a
combiner given those of another deployment of the same format is not warned
(it holds no secret; under the honest-but-curious model above the servers
send the partials of its deployment).
ML adapter¶
FESchemeWrapper runs the key generator
itself, so it holds the master secret key and plays clients, key authority
and decryptor in one trust domain: use it for experiments, not as a
deployment (see pyfe4ai.ml). For
mcfe/ring_lwe_threshold it also runs the decryption servers, so the
threshold adds no protection there; the separate steps
(partial_decrypt_gradients(),
combine_partial_decryptions()) show the
messages of a deployment, whose servers run in their own trust domains.
Gaussian sampling¶
The lattice and DCR proofs sample secrets and noise from the discrete
Gaussian D_{Z,sigma}. There are two samplers.
"facct" (discrete_gaussian_facct())
samples D_{Z,sigma} exactly, to about 2^-185 per sample, for every width
(natively below 2^448). It is the default of these schemes, which record
their sampler as gaussian_sampler in their public parameters: the
Ring-LWE MIFE / MCFE family (sife, mife, mcfe ring_lwe, the
decentralized and threshold MCFE), the dense-LWE MCFE keys t
(mcfe/lwe, fullysec_lwe, lwe_threshold, lwe_decentralized),
sife/fullysec_ring_lwe and, under standard, the noise E of the
ABDP15 public keys (sife/lwe and mife/lwe; mife/lwe_threshold,
whose MIFE layer would do the same, is refused under standard). For
them, in this order: the
gaussian_sampler of the key generator’s or crypto object’s config; else
the one the public parameters record; else, under the toy profile only
and not for sife/fullysec_ring_lwe, the one a gaussian_sampler()
block selects; else "facct". The process-wide choice
(set_gaussian_sampler, PYFE4AI_GAUSSIAN_SAMPLER) does not apply to
them. The standard profile refuses "rounded" for them, and a crypto
object whose config overrides a recorded "facct" with "rounded"
warns (FESecurityWarning; refused under standard).
ABDP15 under toy takes the gaussian_sampler of its key generator’s
config, else the library-wide choice below, and records it as well.
"rounded" rounds a continuous Gaussian. It is the library-wide default,
and so the sampler of the other lattice and DCR schemes unless chosen
otherwise: ALS16 (sife / mife fullysec_lwe), the DCR schemes and,
under toy, ABDP15 SIFE / MIFE LWE (and the keys of tMIFE-LWE); the
schemes above can select it under toy (gaussian_sampler =
"rounded"). The ideal rounded Gaussian (exact uniforms and arithmetic) is
a mixture of centred discrete Gaussians, about 0.02 / sigma^2 from
D_{Z,sigma} per sample: 2^-9 at sigma = 3.2, about 2^-33 per sample at
the Ring-LWE sigma1 – about 2^-18 for one MIFE key of eta ring_n
samples. Its implementations add their own terms (crypto review, October
2026):
the double-precision path (
discrete_gaussian_matrix()and the native kernels, widths up to2^40): the two outputs of a Box-Muller pair share one radius (rings that show in the tail), exact half-integer ties round to even (about2^-53.8 sigmaper sample), and no value exceeds about8.57 sigma(the largest radius 53-bit uniforms give). One ciphertext’s noise is about 2^-12..2^-4 and one key about 2^-25..2^-15 from i.i.d.D_{Z,sigma}, against budgets of 2^-128: use it for toy parameters and benchmarks, not where a proof needsD_{Z,sigma};the MPFR path (
discrete_gaussian_bigint(), wider widths: the DCR keys and masks, all threshold flooding) differs from the ideal rounded Gaussian only by its arithmetic, atbits(sigma) + 320bits (BIGINT_GUARD_BITS:bits(sigma) + stat_param + ceil(log2 N) + 8for every acceptedstat_param, at most 256, and up to 2^56 samples per key). At the earlierbits(sigma) + 128it was 2 to 19 bits short of the budgets. The threshold schemes’ Gaussian flooding always uses it (FLOODING_SAMPLER, recorded in their decryption keys), whatever the sampler selected elsewhere; the default uniform flooding ofmcfe/ring_lwe_thresholduses no Gaussian sampler.
The library-wide choice – which applies to the other schemes and to ABDP15
under toy only – is
made per call (sampler=), per context or per process:
from pyfe4ai.primitives.sampling import gaussian_sampler, set_gaussian_sampler
with gaussian_sampler("facct"): # this context
...
set_gaussian_sampler("facct") # the whole process
or PYFE4AI_GAUSSIAN_SAMPLER=facct in the environment. "facct"
costs 0.5 to 3 microseconds per sample natively (several in CPython). Its
algorithm needs no secret-dependent branches, but CPython and big-integer
arithmetic are not constant-time, so neither sampler resists timing side
channels. For a given bit source its output is the same on every platform
and on both backends, so it comes with known-answer tests. Parties that
derive noise from a shared seed (the Gaussian flooding noise of the
threshold LWE schemes, and of mcfe/ring_lwe_threshold with
flooding="gaussian") must use the same sampler; the default
flooding="uniform" of mcfe/ring_lwe_threshold draws its noise
without a Gaussian sampler (uniform on [-2^tau, 2^tau) from the seeded
SHAKE-256 stream, the same statistical distance per coefficient, see the
module).
The key generator of a scheme that records its sampler publishes it in
pp as the encryptors’ default; public parameters without it (earlier
versions) mean "facct", and decryption does not depend on it. With the rounded
sampler, sife/fullysec_ring_lwe’s keys are 0.02 / sigma1^2 per
sample, over m n eta key samples, from D_{Z,sigma1} for the ideal
rounded Gaussian – in the standard configurations about 2^-47 (elementwise
eta = 1, X = 100), 2^-44.5 (packed eta = 1) and 2^-40.5 (eta =
4, X = Y = 4) – and about 2^-12 at eta = 1 with the
double-precision path’s artifacts, terms its adaptive proof does not budget.
Status API¶
SchemeStatus, which this module re-exports,
is documented with the scheme registry (pyfe4ai.core.registry).
Review status of every registered scheme.
Each registered (family, variant) has a
SchemeStatus, declared with the scheme in
pyfe4ai.core.registry (which also defines the status and fidelity
values). This module derives the status table from the registry and
provides what uses it: the queries, the
FESecurityWarning emitted when a
known-insecure key generator or crypto object is instantiated, and the
README Scheme Status table (markdown_table()). All schemes
additionally share the caveats of the README (research prototype, toy
default parameters, no side-channel hardening).
- pyfe4ai.core.status.SCHEME_STATUS: dict[tuple[str, str], SchemeStatus]¶
Review status of every registered
(family, variant), derived frompyfe4ai.core.registry.SCHEMES(in its order): the source of the README Scheme Status table and of the status table of the docs.
- pyfe4ai.core.status.get_scheme_status(family, variant=None)[source]¶
Return the review status of a registered scheme:
(family, variant), or its id"family/variant"alone.- Raises:
KeyError – If the scheme is not registered.
- Parameters:
- Return type:
- pyfe4ai.core.status.status_for_module(module)[source]¶
Return
((family, variant), status)for a scheme module, if registered.
- pyfe4ai.core.status.warn_if_known_insecure(module, stacklevel=None)[source]¶
Emit
FESecurityWarningif module implements a known-insecure scheme, attributed to the application’s call (the first frame outside pyfe4ai,warn_at_caller()), or stacklevel frames up if one is given.
- pyfe4ai.core.status.markdown_table()[source]¶
Render
SCHEME_STATUSas the README Scheme Status table.- Return type:
Profiles API¶
Security profiles: parameter presets for the key generators.
The security_profile entry of a key generator’s config selects one:
"toy"(default)The library’s small defaults – fast enough for tests and demos, and not secure. A config without the entry, or with
"toy", is used exactly as given."standard"Parameters aiming at 128-bit classical security where this prototype can reach it, chosen per scheme family:
discrete log (DDH, Damgard / MDDH and their MIFE / MCFE variants): a 3072-bit safe-prime group, the RFC 3526 MODP group 15 (NIST SP 800-57 Part 1 Rev. 5, Table 2: L = 3072 for 128 bits). The decentralised
mcfe/ddh_decentralizedthen needs a DCR modulus of about 6410 bits for combining key shares, whose safe primes take minutes to generate;DCR (Paillier variants):
Nof about 3072 bits (two 1536-bit safe primes);DDH over ristretto255 (
*/ddh_ristretto255): the group is fixed, of order about2^252(Pollard rho about2^126, the 128-bit class of X25519 / Ed25519); the profile sets nothing;Ring-LWE:
kappa = 128and the smallest ring dimension whose derived modulusqmeetsRING_LWE_128_LOG_Q, a lattice-estimator table (the method of the LWE tables) read at the smallest width among the RLWE problems of the scheme’s proof (about 8 for the BMMS21 parameters of Sec. 4.2 and 5;log2 q<= 31 / 57 / 111 / 218 / 435 / 872 for n = 1024 … 32768 at that width). It replaces the Homomorphic Encryption Standard’s bound, which this estimator puts at about 125 bits;sife/fullysec_ring_lwe(BMMS21 Sec. 5, adaptive) also picks its numbermof key polynomials: the smallest one whoseqmeets that bound;dense LWE, the ABMPSW20 MCFE family (
mcfe/lwe,fullysec_lwe,lwe_threshold,lwe_decentralized):lwe_n = "auto", the smallest dimensionn0whose derivedqmeetsDENSE_LWE_128_LOG_Q– a lattice estimator table for LWE(n0, q, ceil(2 sqrt(n0))) with a uniform secret, the problem of the scheme’s security proof. These schemes have no public matrix: a label is hashed ton0 + m0values and each ciphertext is one inner product, cheaper than a 3072-bit DDH ciphertext. The decentralised variant combines key shares under a DCR modulus of at least 3072 bits (STANDARD_DCR_PRIME_BITSper prime), so its key derivation is not post-quantum;LWE with a seeded public matrix, the ABDP15 IPFE (
sife/lwe,mife/lwe):lwe_n = "auto", the smallest dimension whose(q, sigma')meetsWIDE_LWE_128_LOG_RATIO, a lattice estimator table for LWE with a uniform secret, read at the error widthsigma' = sigma / (1 + B sqrt(eta))of the LWE problem the security proof reduces to (B = 2 X, or4 Xin the slots ofmife/lwe; ABDP15 full version, Thm. 4.4, with the width derived in the proof of Thm. 6.6; seepyfe4ai.schemes.common.abdp15_lwe). That giveslwe_nof about 900 to 1700 for small bounds; reading the table at the public key’s ownsigmawould give 14 to 40 percent less forX = Y >= 8.A(m ~ lwe_n log2 qrows, 10^8 to 4 * 10^8 entries) is published as a seed;matrix_modechooses between keeping it expanded in memory (about 0.1 to 0.3 s per encryption, 2 to 6 GB) and expanding it for every batch ("stream": seconds per batch, about 0.5 GB). The noiseEof the public keys is sampled exactly ("facct";"rounded"is refused);pairing-based schemes: BLS12-381 (the Rust extension) – about 120 to 126-bit security after the exTNFS attacks on its 381-bit field (Barbulescu and Duquesne, J. Cryptol. 2019), below the 128-bit target; a
FESecurityWarningsays so.
Refused, because no parameter set is both secure and usable in pure Python:
sife/fullysec_lweandmife/fullysec_lwe(ALS16: at a dimension the lattice estimator puts at 128 bits, n = 3328 to 4352 forX = Y <= 50andeta <= 10, and withm = 4 n log2 qas its Theorem 2 requires, the public matrix has 1 to 2 * 10^10 entries and a ciphertext 2.9 to 4.5 * 10^6 coordinates of 219 to 258 bits),mife/lwe_threshold. Atsigma'its flooding-enlargedq(stat_param = 128, two clients) needs an LWE dimension at the very end of the table (5888 to 6144,Aof 6.5 to 7.8 * 10^9 entries) for a few small bounds, e.g.X = Yin {1, 2, 3, 8, 10} ateta = 1, and beyond it for most others (X = Y= 4 to 6,X = Y >= 12, mosteta >= 2; about 6500 forX = Y = 50). The opt-in KL accounting of the flooding noise (t = sonly, with an explicit budget and a weaker guarantee) would take about 4864, but the refusal holds with either accounting. Also refused:mcfe/paillier_decentralized(its key shares are combined under a DCR modulus of more than 15000 bits).The statistical parameter
stat_param(rounding and leftover-hash slack of ABMPSW20, flooding of the threshold schemes, the masks ofmcfe/ddh_decentralizedand the Paillier and MCFE2 key distributions) is 128, askappaof the Ring-LWE schemes: a statistical distance of2^-128per sample, so thatQsamples stay belowQ 2^-128. That holds for exact Gaussians (the"facct"sampler, the default of the Ring-LWE MIFE / MCFE family, the dense-LWE MCFE keys, SIFE FullySec Ring-LWE and, understandard, the ABDP15 public keys) and for the MPFR path atbits(sigma) + 320bits; the double-precision rounded sampler does not meet it (see the security notes in the documentation).mcfe/ring_lwe_thresholdwitht = s(Shamir sharing, Gaussian flooding) also accepts, as an explicit opt-in that the profile never sets,flooding_accounting = "kl"with a mandatorymax_partial_decryptions(mife/lwe_thresholdtakes it too, but only undertoy: this profile refuses that scheme with either accounting). Therestat_parambounds the Hellinger distance between the adversary’s real and simulated views of a run in which every server produces at most that many partial decryptions, instead of the per-sample statistical distance above:stat_param - 6.85bits of statistical security in the bit-security framework of Micciancio and Walter for decision games, or about2^-65of total statistical distance read conventionally. The servers count against the limit in a budget that the deployment gives them and must keep across processes and restarts. A different and weaker guarantee, with its own parameter records; seepyfe4ai.schemes.threshold.kl.Values given explicitly in the config must not be weaker than the profile’s.
The profile’s rules – its minima and presets per kind
(pyfe4ai.core.config) and the refusals (each scheme’s refused
in pyfe4ai.core.registry) – are applied by
pyfe4ai.core.config.resolve() when a key generator is built; this
module names the profiles and the kind of every scheme.
- pyfe4ai.core.profiles.SCHEME_KIND¶
Kind of every registered
(family, variant)(the parameters the profiles size:pyfe4ai.core.registry.KINDS), derived from the registry.
- pyfe4ai.core.profiles.STANDARD_DCR_PRIME_BITS = 1536¶
Bits of each prime of a DCR modulus under
standard(Nof 3072 bits).
- pyfe4ai.core.profiles.STANDARD_STAT_PARAM = 128¶
Statistical parameter under
standard(minimum and default).
- pyfe4ai.core.profiles.MAX_STAT_PARAM = 256¶
Largest statistical parameter a key generator accepts, in both profiles; the MPFR Gaussians’ guard bits (
BIGINT_GUARD_BITS) coverstat_param + ceil(log2 N) + 8up to this value.