Skip to content
Functional Encryption

Functional Encryption

Functional Encryption (FE) lets a key holder learn a function of the plaintext without revealing the plaintext itself. From a ciphertext of yy and a functional key for a function ff, decryption returns only f(y)f(y).

A common CTF instantiation is FE for inner products, where a key for a vector xx reveals only x,y\langle x, y \rangle. It is often built on an elliptic curve, following the paper Simple Functional Encryption Schemes for Inner Products on a NIST curve.

Inner-product scheme

The setup samples two secret scalar vectors s,ts, t and publishes hi=sig+tihh_i = s_i g + t_i h for two generators g,hg, h of the curve.

  • Encryption of a binary vector yy uses a random scalar rr: C=rg,D=rh,Ei=yig+rhiC = r g, \qquad D = r h, \qquad E_i = y_i g + r h_i
  • A functional key for a vector xx is the pair (sx, tx)(s \cdot x,\ t \cdot x) (dot products over GF(ord)GF(\text{ord})).
  • Decryption with that key returns only x,yg\langle x, y \rangle \cdot g, never yy directly: ixiEi(sx)C(tx)D=x,yg\textstyle\sum_i x_i E_i - (s \cdot x) C - (t \cdot x) D = \langle x, y \rangle \cdot g

Attacks

  • Key oracle leaking the master key

    If the key-generation oracle returns both the query vector xx and its key (sx, tx)(s \cdot x,\ t \cdot x), every query is a linear equation over GF(ord)GF(\text{ord}) in the unknown ss and tt. Collecting nn queries (where nn is the vector length) gives two invertible systems Ys=(sx)Y s = (s \cdot x) and Yt=(tx)Y t = (t \cdot x), where YY is the matrix of the query vectors. Recovering (s,t)(s, t) lets you decrypt each bit directly:

    EisiCtiD=yig{O, g}E_i - s_i C - t_i D = y_i \cdot g \in \lbrace \mathcal{O},\ g \rbrace

    so yi=0y_i = 0 if the result is the point at infinity and yi=1y_i = 1 if it equals gg (no discrete log needed, just a point equality).

  • Per-ciphertext blinding defeated by collinearity

    A patched scheme masks every bit with a fresh scalar α\alpha (Ei=yiαg+rhiE_i = y_i \cdot \alpha g + r h_i), so the residue becomes x,yαg\langle x, y \rangle \cdot \alpha g and the {O,g} \lbrace \mathcal{O}, g \rbrace test no longer works. But for each known (xi,sxi,txi)(x_i, s\cdot x_i, t\cdot x_i) the partial decryption

    Qi=jxi[j]Ej(sxi)C(txi)D=xi,yαg=ciPQ_i = \textstyle\sum_j x_i[j] E_j - (s \cdot x_i) C - (t \cdot x_i) D = \langle x_i, y \rangle \cdot \alpha g = c_i \cdot P

    is a small integer multiple (ci=xi,y[0,N]c_i = \langle x_i, y \rangle \in [0, N]) of the same hidden point P=αgP = \alpha g. Recovering the small cic_i is not a discrete log: tabulate {aQ0} \lbrace a \cdot Q_0 \rbrace for a reference Q0Q_0 and match bQib \cdot Q_i against it (a baby-step over small multiples) to read each ratio ci/c0c_i / c_0, then lift to integers with an lcm\text{lcm}. If the secret yy persists across re-keys, aggregating enough rounds yields far more than NN linear equations xi,y=ci\langle x_i, y\rangle = c_i and yy is the unique solution over Q\mathbb{Q}.