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 (s⋅x, t⋅x)(s \cdot x,\ t \cdot x) (dot products over GF(ord)GF(\text{ord})).
  • Decryption with that key returns only ⟨x,y⟩⋅g\langle x, y \rangle \cdot g, never yy directly: ∑ixiEi−(s⋅x)C−(t⋅x)D=⟨x,y⟩⋅g\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 (s⋅x, t⋅x)(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=(s⋅x)Y s = (s \cdot x) and Yt=(t⋅x)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:

    Ei−siC−tiD=yi⋅g∈{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,s⋅xi,t⋅xi)(x_i, s\cdot x_i, t\cdot x_i) the partial decryption

    Qi=∑jxi[j]Ej−(s⋅xi)C−(t⋅xi)D=⟨xi,y⟩⋅αg=ci⋅PQ_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 {a⋅Q0} \lbrace a \cdot Q_0 \rbrace for a reference Q0Q_0 and match b⋅Qib \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}.