Quadratic FE

Quadratic functional encryption schemes: the key generator and crypto class of every scheme of the family (the registry: pyfe4ai.core.registry).

The key generator and crypto class of every scheme below are importable from pyfe4ai.schemes.quadratic.

SGP (Single-Input)

Public-key functional encryption for quadratic polynomials (SGP) | “Reading in the Dark: Classifying Encrypted Digits with Functional Encryption” | By Dufour-Sans, Gay, Pointcheval (ePrint 2018/206) – Fig. 2.

  • type: public-key encryption; keys for matrices F, decryption gives x^T F y

  • setting: asymmetric pairing group (default BLS12-381); IND-CPA in the generic bilinear group model

s, t <- Z_p^n; pk = (g1^s, g2^t), msk = (s, t).

  • Enc(pk, x, y): gamma <- Z_p, W <- GL_2; a_i = (W^{-1})^T (x_i, gamma s_i), b_i = W (y_i, -t_i); ct = (g1^gamma, {g1^{a_i}, g2^{b_i}}) – computed from pk.

  • KeyGen(msk, F): dk = (g2^{f(s, t)}, F) with f(s, t) = sum f_ij s_i t_j.

  • Dec: e(g1^gamma, g2^{f(s,t)}) prod e(g1^{a_i}, g2^{b_j})^{f_ij} = [x^T F y]_T and a discrete log in [-n^2 B^3, n^2 B^3].

Signed inputs with one bound B for x, y and F. Versions <= 0.2.0 encrypted with (s, t) themselves (GoFE’s secret-key form) and handed them to every encryptor, which made each encryptor a key authority.

class pyfe4ai.schemes.quadratic.sgp.QuadraticSGPKeyGenerator(config, **kwargs)[source]

Bases: IPFEAbsKeyGenerator, ParameterCacheMixin

Setup and key generation of DSGPP18’s quadratic FE (Fig. 2).

Parameters:

config (dict)

__init__(config, **kwargs)[source]

Initialise the DSGPP18 quadratic FE key generator.

Parameters:

config (dict) – Scheme configuration. Recognised keys: n (vector length, or eta; default 2), bound (one bound for x, y and F, default 16) and pairing_group_param (asymmetric group, default "BLS12-381").

Return type:

None

setup()[source]

Generate master public and secret keys for the scheme.

Return type:

None

get_public_parameters(**kwargs)[source]

Return serialisable public parameters.

Return type:

dict | None

Returns:

A dict of public parameters, or None on error.

get_private_keys(nid='nid_default', **kwargs)[source]

Public-key scheme: encryption needs pk only (None).

Versions <= 0.2.0 returned the master secret key (s, t).

Parameters:

nid (str, default: 'nid_default')

Return type:

dict | None

get_decryption_keys(sid, **kwargs)[source]

Derive a functional decryption key for a matrix F.

Parameters:
  • sid (str) – Session identifier.

  • **kwargs – Must include credentials with function_matrix (n x n integer matrix F).

Return type:

dict | None

class pyfe4ai.schemes.quadratic.sgp.QuadraticSGP(config, **kwargs)[source]

Bases: IPFEAbsCrypto

Encryption (from pk) and decryption of DSGPP18’s quadratic FE.

Parameters:

config (dict)

__init__(config, **kwargs)[source]

Initialise the DSGPP18 quadratic FE crypto object.

Parameters:

config (dict) – Must contain keys with pp (public parameters, which hold the public key).

Return type:

None

encrypt(payload)[source]

Enc(pk, (x, y)) for n integers each, bounded by bound.

Parameters:

payload (dict)

Return type:

dict

decrypt(ct, dk)[source]

Decrypt ciphertexts and recover the inner product.

Parameters:
  • ct (dict) – Ciphertext dict.

  • dk (dict) – Functional decryption key.

Return type:

int | None

encrypt_lst_ndarray(lst_ndarray, **kwargs)[source]

Encrypt pairs (x, y) of ndarrays element-wise.

Parameters:
  • lst_ndarray (list) – The n arrays of x (one per coordinate), all of one shape, scaled by 10^precision.

  • **kwargs – Must include rhs_lst_ndarray, the n arrays of y.

Returns:

the object array of ciphertexts.

Return type:

A one-element list

compute_lst_ndarray_ct(dict_ndarray_ct, **kwargs)[source]

Compute inner products on encrypted ndarray ciphertexts.

Parameters:

dict_ndarray_ct (dict) – Encrypted ndarray ciphertexts (list or dict).

Return type:

list | None

decrypt_lst_ndarray_ct(dict_ndarray_ct, **kwargs)[source]

Decrypt encrypted ndarray ciphertexts element-wise.

Parameters:

dict_ndarray_ct (dict) – Encrypted ndarray ciphertexts (list or dict).

Return type:

list | None

Multi-Input Quadratic FE (AGT22)

Multi-input functional encryption for quadratic functions (cross-user terms) | Agrawal, Goyal, Tomida, “Multi-Input Quadratic Functional Encryption: | Stronger Security, Broader Functionality”, TCC 2022 (ePrint 2022/1168) – | Section 5: MIFE for quadratic functions in which every user has its own | encryption key and any subset of users may be corrupted. Building blocks | as in the paper: the function-hiding IPFE of [TAO20] recalled in Sec. 5.1, | the function-hiding SK-MCFE for inner products of Fig. 9 and the SK-MCFE | for mixed-group inner products of Sec. 3 / Fig. 1.

  • type: multi-input FE with per-user encryption keys

  • setting: asymmetric pairing group (default BLS12-381); selective pos message-hiding security (Thm. 5.1) from MDDH_1 (SXDH, for the TAO20 IPFE), bilateral MDDH_k with k >= 2 (for the mixed-group SK-MCFE) and PRF security

Function class (Def. 2.9): n users with m integers each, f(x_1, ..., x_n) = sum_{i < k} sum_{j, l} c[(i, j, k, l)] x_i[j] x_k[l] – only terms between different users. c is given as an (n m) x (n m) matrix C[(i - 1) m + j][(k - 1) m + l] whose blocks with i >= k are zero.

Building blocks (all over the same pairing group):

  • _TAO20: B <- GL_{d+3}(Z_p), B* = (B^{-1})^T; Enc([x]_1; r) = [(x, r, 0, 0) B]_1, KeyGen([y]_2; s) = [(y, 0, s, 0) B*]_2, Dec = prod e(ct_j, sk_j) = [<x, y>]_T; linear in (x, r) / (y, s).

  • _ICFE (Fig. 9): one _TAO20 per slot; Enc(i, lab, x) = Enc_i((x, 0^L, PRF(K, lab), 0)), keys for (y_i, 0^L, r_i, 0) with sum r_i = 0.

  • _MGFE (Fig. 1): Enc(i, lab, ([x1]_1, [x2]_2)) with z <- Z_p^k gives icEnc((x1, 0^m2, z, 0)) and the IPFE key of (x2, -z, 0); keys with a <- Z_p^k give icKeyGen((y1_i, 0^m2, a, 0))_i and IPFE ciphertexts of (y2_i, a, 0).

The MIFE (Sec. 5.2): the authority samples w_(i,j,k,l), u_ij, u~_ij, v_ij, v~_ij and the master keys, and gives user i the encryption key EK_i = master ciphertexts MstEnc(i, e_j) (j <= m) and MstEnc(i, 0) (D = 4m + 2k + 17 of them). A user encrypts by the homomorphic combination sum_j x[j] MCT1_j - (sum_j x[j] - 1) MCT0_1 + sum_j gamma_j (MCT0_2j - MCT0_2j+1). MstEnc encodes b_j = (x[j], 0, s e_(i,j), r u_ij, v_ij, 0^3m) as IPFE ciphertexts, b~_j = (x[j], 0, s~ w_(*,*,i,j), u~_ij, t v~_ij, 0^3m) as IPFE keys, (s, 0) / (s~, 0) under a second IPFE and f = (r, t, 0^{m^2 n}), h = 0 under the mixed-group SK-MCFE with the fixed label lab0. A key for c is (c, mgKeyGen({f~_i, h~_i}), {sigma_ik}); decryption returns z1 - z2 - z3 (Sec. 5.2) and a discrete log in [-m^2 n^2 C X^2, m^2 n^2 C X^2].

Deviations: PRF = HMAC-SHA512 reduced mod p; only the pos variant (every user must contribute a ciphertext, Remark 2.6; the generic any-transform is not implemented); iSetup(1^lambda; PRF(K, lab0)) is realised as one IPFE instance sampled at setup. Encryption keys are large ((m + D) master ciphertexts per user) and encryption costs a few thousand exponentiations for small n, m.

class pyfe4ai.schemes.quadratic.miqfe.QuadraticMIQFEKeyGenerator(config, **kwargs)[source]

Bases: IPFEAbsKeyGenerator

Setup and key generation of the AGT22 MIFE for quadratic functions.

Parameters:

config (dict)

__init__(config, **kwargs)[source]

Initialise the key generator.

Parameters:

config (dict) – n (users, >= 2), lst_nid, m (integers per user), bound_x (X), bound_c (C), mddh_k (k >= 2, default 2) and pairing_group_param (asymmetric, default BLS12-381).

Return type:

None

setup()[source]

Sample the master key and every user’s encryption key (master ciphertexts).

Return type:

None

get_public_parameters()[source]

Group description, generators and dimensions.

Return type:

dict

get_private_keys(nid, **kwargs)[source]

User nid’s encryption key: its master ciphertexts only (no master secret).

A corrupted user learns its own key; together with a functional key for c it can still evaluate c on its own chosen inputs, which the functionality allows (e.g. sum_l c[(i,j,k,l)] x_k[l]).

Parameters:

nid (str)

Return type:

dict | None

get_decryption_keys(sid, **kwargs)[source]

Key for c (credentials["coefficients"], an nm x nm matrix).

Entries in blocks (i, k) with i >= k must be zero (Def. 2.9).

Parameters:

sid (str)

Return type:

dict | None

class pyfe4ai.schemes.quadratic.miqfe.QuadraticMIQFE(config, **kwargs)[source]

Bases: IPFEAbsCrypto

Encryption with EK_i and decryption of the AGT22 MIFE.

Parameters:

config (dict)

__init__(config, **kwargs)[source]

Initialise with keys.pp and, for users, keys.sk (their EK_i).

Parameters:

config (dict)

Return type:

None

encrypt(lst_pt)[source]

Homomorphic combination of this user’s master ciphertexts (Sec. 5.2 Enc).

Parameters:

lst_pt (list)

Return type:

dict

decrypt(dct_ct, dk)[source]

z = z1 - z2 - z3 (Sec. 5.2 Dec) and a bounded discrete log.

Raises:

FESchemeError – Unless every user contributes a ciphertext.

Parameters:
Return type:

int | None

encrypt_lst_ndarray(lst_ndarray, **kwargs)[source]

Not provided: encryption keys and costs are large; use encrypt().

Parameters:

lst_ndarray (list)

Return type:

list | None

compute_lst_ndarray_ct(dict_ndarray_ct, **kwargs)[source]

Not provided (see encrypt_lst_ndarray()).

Parameters:

dict_ndarray_ct (dict)

Return type:

list | None

decrypt_lst_ndarray_ct(dict_ndarray_ct, **kwargs)[source]

Not provided (see encrypt_lst_ndarray()).

Parameters:

dict_ndarray_ct (dict)

Return type:

list | None

Quad

Public-key functional encryption for degree-2 polynomials (Quad) | “A New Paradigm for Public-Key Functional Encryption for Degree-2 Polynomials” | By Romain Gay, PKC 2020 (ePrint 2020/093) – Fig. 4 (Quad), CPA variant, | over the partially function-hiding IPFE of Fig. 8 with k = 1.

  • type: public-key encryption; keys for matrices F, decryption gives x^T F y

  • setting: asymmetric pairing group (default BLS12-381); semi-adaptive simulation security from bilateral DLIN, DDH in G1 and SXDH

Setup: a <- DDH ((1, a)), B <- DLIN ([[b1, 0], [0, b2], [1, 1]]), U in Z_p^{n x 2}, V in Z_p^{m x 3} and M = [[a (x) (Id_m | V B), 0], [0, Id_n (x) B]] of size (2m + 3n) x (m + 2 + 2n); the IPFE is set up for [M]_1 and pk = ([U a]_1, [V B]_2, pk_IPFE).

  • Enc(x, y): r <- Z_p, s <- Z_p^2; ct_x = [x + U a r]_1, ct_y = [y + V B s]_2, ct_IPFE = Enc_IPFE(r (y ; s) ; x (x) s).

  • KeyGen(F): sk_F = (F, KeyGen_IPFE(vect(U^T F) ; vect(F V))).

  • Dec: e(ct_x, F ct_y) / Dec_IPFE = [x^T F y]_T and a discrete log bounded by n m B^3.

The IPFE (Fig. 8, CPA, no QANIZK): a', b' <- (1, Z_p), U' in Z_p^{(N+2) x 2}, V' in Z_p^{N x 2}, pk_IPFE = ([a']_1, [U' a']_1, [V'^T M]_1, [M]_1); Enc_IPFE(t) = [c = a' r' ; (-V'^T M t ; M t) + U' c]_1 computed from [M]_1 (M contains the secrets a, B, V B); KeyGen_IPFE(z) = [(-U'^T w ; w)]_2 with w = (b' s' ; z + V' b' s'); Dec_IPFE = prod e(ct_j, sk_j) = [<M t, z>]_T.

As in the paper, M is not of full column rank (the a (x) V B columns are combinations of the a (x) Id_m ones); the redundant columns are what lets the encryptor form r (y + V B s) from [M]_1.

A ciphertext has 4n + 2m + 4 elements of G1 and m of G2. Signed inputs (|x_i|, |y_j|, |F_ij| <= B): the discrete log is searched in [-n m B^3, n m B^3]. Versions <= 0.2.0 encrypted x (x) y with an IPFE instead (ciphertexts of n m elements, not this construction).

class pyfe4ai.schemes.quadratic.quad.QuadraticQuadKeyGenerator(config, **kwargs)[source]

Bases: IPFEAbsKeyGenerator

Setup and key generation of Gay20’s Quad.

Parameters:

config (dict)

__init__(config, **kwargs)[source]

Initialise the key generator.

Parameters:

config (dict) – n (length of x), m (length of y), bound (B on every entry of x, y and F) and pairing_group_param (asymmetric, default BLS12-381).

Return type:

None

setup()[source]

Sample a, B, U, V, build [M]_1 and set up the IPFE.

Return type:

None

get_public_parameters(**kwargs)[source]

The public key ([U a]_1, [V B]_2, pk_IPFE) and the dimensions.

Return type:

dict | None

get_private_keys(nid='nid_default', **kwargs)[source]

Public-key scheme: encryption needs the public key only.

Parameters:

nid (str, default: 'nid_default')

Return type:

dict | None

get_decryption_keys(sid, **kwargs)[source]

sk_F = (F, KeyGen_IPFE(vect(U^T F) ; vect(F V))).

Parameters:
  • sid (str) – Session identifier (unused).

  • **kwargs – credentials with function_matrix (n x m integers bounded by bound).

Return type:

dict | None

class pyfe4ai.schemes.quadratic.quad.QuadraticQuad(config, **kwargs)[source]

Bases: IPFEAbsCrypto

Encryption and decryption of Gay20’s Quad.

Parameters:

config (dict)

__init__(config, **kwargs)[source]

Initialise with keys.pp (the public key).

Parameters:

config (dict)

Return type:

None

encrypt(payload)[source]

Encrypt {"x": n integers, "y": m integers} (entries bounded by bound).

Parameters:

payload (dict)

Return type:

dict

decrypt(ct, dk)[source]

log(e(ct_x, F ct_y) / Dec_IPFE); None beyond n m B^3.

Parameters:
Return type:

int | None

encrypt_lst_ndarray(lst_ndarray, **kwargs)[source]

Encrypt position-wise pairs (x, y) taken from n and m arrays.

Parameters:

lst_ndarray (list)

Return type:

list | None

compute_lst_ndarray_ct(dict_ndarray_ct, **kwargs)[source]

Decrypt position-wise (delegates to decrypt_lst_ndarray_ct()).

Parameters:

dict_ndarray_ct (dict)

Return type:

list | None

decrypt_lst_ndarray_ct(dict_ndarray_ct, **kwargs)[source]

Decrypt ndarray ciphertexts element-wise (results scaled by 10^(2 precision)).

Parameters:

dict_ndarray_ct (dict)

Return type:

list | None