ZK/SEC Research notes from zkSecurity
All posts
educative · zk

WE-KZG: Encrypt to KZG.

Polynomials

Can you create a ciphertext that can be decrypted if the polynomial inside a polynomial commitment has a particular evaluation? Yes and it turns out to not be that complicated...

Today we will look at the construction from our recent Asiacrypt 2024 paper, which enables just that for standard KZG commitments. So come along and let's dive into the world of Witness Encryption for KZG commitments.

Introduction to Witness Encryption (WE)

In public key encryption schemes, there are two types of keys: a public key and a secret key. Encryption takes a public key and a message and produces a ciphertext:

$$ \mathsf{ct} \gets \mathsf{Enc}(\mathsf{pk}, \mathsf{msg}) $$

While decryption requires the secret key:

$$ \mathsf{msg} \gets \mathsf{Dec}(\mathsf{sk}, \mathsf{ct}) $$

Without knowledge of the secret key, the ciphertext hides the message.

Witness encryption is similar, but instead of having the public/secrets keys being generated by a $(\mathsf{pk}, \mathsf{sk}) \gets \mathsf{KeyGen}()$ algorithm, the "public key" is a statement $\mathsf{x}$ and the secret key is a witness $\mathsf{w}$ for that statement ("why it is true") i.e.

$(\mathsf{x}, \mathsf{w}) \in \mathcal{R}$

. Meaning you can "encrypt" to statements, without knowing the witness or even if the statement is true.

For instance, you could encrypt to the statements/relations such as:

Encrypt to Sudoku: $\mathsf{w}$ is a solution to this Sudoku puzzle $\mathsf{x}$.

Encrypt to Hash: $\mathsf{w}$ is preimage of the SHA3 hash $\mathsf{x}$, i.e. $\mathsf{SHA3}(\mathsf{w}) = \mathsf{x}$.

Technically, what we require is extractable witness encryption, where, not only is $\mathsf{x}$ in the language (e.g. the Sudoku puzzle has a solution), but the decryptor is garuenteed to know the witness $\mathsf{w}$ (e.g. the Sudoku solution).

Witness encryption for all of NP from standard assumptions is ongoing research, but we can construct it efficiently for specific languages and today we are going to show how to construct a witness encryption scheme for a particular language, namely opening proofs of KZG commitments:

$$ \mathcal{R} = \{ (\mathsf{x} = (\mathsf{com}, x, y), \mathsf{w} = \pi) \mid \mathsf{Verify}(\mathsf{com}, x, y, \pi) = 1 \} $$

In other words: you can encrypt to a KZG commitment and "evaluation claim" $(\mathsf{com}, x, y)$, which can only be decrypted if the decryptor knows a valid KZG opening proof $\pi$, i.e. the polynomial "inside" the commitment evaluates to $y$ at $x$.

Witness Encryption for KZG Openings

The construction is actually surprisingly simple (and pretty elegant), although the security proof is more involved. Let us briefly recall how the pairing-based KZG commitment scheme works:

  1. Setup: the setup consistens of "powers of tau":
$$ ( [\tau]_2, [\tau]_1, [\tau^2]_1, [\tau^3]_1, \ldots, [\tau^d]_1) $$

Where we use the notation $[v]_1$ to denote $v = G_1^v$ where $G_1$ is a generator of $\mathbb{G}_1$ and $[v]_2$ to denote $v = G_2^v$ where $G_2$ is a generator of $\mathbb{G}_2$.

  1. Commit: a commitment is formed by homomorphically evaluating the polynomial $f(X)$ at $\tau$:
$$ f(X)= \sum_{i=0}^{d} f_i X^i $$ $$ \mathsf{com} = f(\tau) = \sum_{i=0}^{d} \left[f_i \cdot \tau^i\right]_1 = \sum_{i=0}^{d} f_i \cdot [\tau^i]_1 $$

The inuition is essentially Swartz-Zippel + "encryption" of $\tau$: to find a collision between commitments he must find two polynomials that agree at $\tau$ -- but that is hard because the exponentiation $[\tau^i]_1 = G_1^v$ hides the evaluation point $\tau$.

  1. Open: opening at $x$ to $y$ is done by committing to the quotient polynomial:
$$g(X) = \frac{f(X) - y}{X - x}$$ $$\pi \gets \mathsf{Commit}(g)$$

This follows from the simple observation that if $f(x) = y$ then $f(x) - y = 0$ aka.

$f(X) - y$

has a root at . This is equivalent to dividing . So $g(X)$ is a polynomial (as opposed to a rational function) if and only if $f(x) = y$.

  1. Verify: the pairing can be used to multiply committed polynomials by degree 1 polynomials. This is exploited to "multiply out" the denominator of the quotient polynomial and check for equality. Concretely, the verifier checks:
$$ e(\pi, [\tau]_2 \- \[x]_2) = e(\mathsf{com} - y, [1]_2) $$

Here $[\tau]_2 \- \[x]_2$ is a commitment to the degree 1 polynomial $X - x$ in the second group.

Encryption Time!

The trick to constructing witness encryption for KZG commitments is to look at the final verification equation and try to randomize one side of the equation. The verification equation is:

$$ e(\pi, [\tau]_2 \- \[x]_2) = e(\mathsf{com} - y, [1]_2) $$

If we pick $r \in \mathbb{Z}_{p}$ and raise both sides to $r$, the relation still holds:

$$ e(\pi, [\tau]_2 \- \[x]_2)^r = e(\mathsf{com} - y, [1]_2)^r $$

We can move the exponents inside the pairing:

$$ \color{red}{e(\pi, r \cdot ([\tau]_2 - \[x]_2)) } = \color{green}{e(\mathsf{com} - y, [r]_2)} $$

To build public key encryption, the observation is that the encryptor can pick an $r$ and compute the green part without knowing $\pi$. At the same time, even if you are given $s = r$ $\cdot ([\tau]_2 $ - $ \[x]_2)$ $ \in \mathbb{G}_2$ it is hard to compute the red part without knowing $\pi$. We show in the paper that finding $\pi$ st. $e(\pi, s) = e(\mathsf{com} - y, [r]_2)$ is equivalent to computing a KZG opening proof in a model called "the algebraic group model" AGM which is the same model commonly used to prove extractability of KZG commitments themselves.

Putting everything together, we can construct the encryption scheme as follows:

Encryption:

  1. Pick a random $r \in \mathbb{Z}_p$.

  2. Compute $s \gets r \cdot ([\tau]_2 \- \[x]_2)$.

  3. Compute $k \gets \mathsf{Hash}\left(e(\mathsf{com} - y, [r]_2)\right)$ to get a symmetric key $k$.

  4. Encrypt the message $\mathsf{msg}$ with the symmetric key $k$: $\mathsf{c} = \mathsf{Enc}_{k}(\mathsf{msg})$.

  5. Output $\mathsf{ct} = (s, \mathsf{c})$.

Decryption:

  1. Compute the KZG opening proof $\pi$ as normal.

  2. Compute $k \gets \mathsf{Hash}\left(e(\pi, s)\right)$.

  3. Decrypt the ciphertext $\mathsf{c}$ with the symmetric key $k$: $\mathsf{msg} = \mathsf{Dec}_{k}(\mathsf{c})$.

  4. Output $\mathsf{msg}$.

As you can see, encrypting and decryption from/to a KZG opening is essentially the same cost as KZG itself. Even though the scheme is pretty simple, there are some more/less surprising applications. Maybe you can think of some yourself?

Let us look at an easy one.

Application: Laconic Oblivious Transfer

In an Oblivious Transfer (OT) protocol, there are two parties: a sender and a receiver. The sender has two messages $m_0$ and $m_1$ and the receiver has an bit $b \in \{0, 1\}$. The goal is for the receiver to learn his chosen message $m_b$ without the sender learning $b$ or the receiver learning the other message $m_{1-b}$. Basically a "chose one-of-two messages without telling me"-protocol.

Oblivious transfer has been especially useful in the context of secure multi-party computation.

OT

Laconic Oblivious Transfer is a variant of Oblivious Transfer (OT) but where the communication complexity is reduced: the receiver (Bob in the diagram) can commit to many different choices $b_1, b_2, \ldots, b_n \in \{0, 1\}$ using a very short commitment $\mathsf{com}$. The sender (Alice in the diagram) can then encrypt messages $m_0, m_1$ to any position $i$ such that Bob only learns $m_{b_i}$ without Alice learning $b_i$. With our new KZG witness encryption scheme, we can easily construct an efficient laconic OT protocol as follows:

  • Commit: Bob interpolates a polynomial $f(X)$ such that $f(i) = b_i$. He then commits to the polynomial $f(X)$ using a KZG commitment $\mathsf{com}$.

  • Encrypt: Alice uses the KZG witness encryption scheme to encrypt $m_0$ and $m_1$ to $\mathsf{x} = (\mathsf{com}, i, 0)$ and $\mathsf{x} = (\mathsf{com}, i, 1)$ respectively. Obtaining ciphertexts $\mathsf{ct}_0$ and $\mathsf{ct}_1$, corresponding to the two contractory claims that $f(i) = 0$ and $f(i) = 1$ respectively.

  • Decrypt: Bob can compute the KZG opening proof $\pi$ for the evaluation $f(i) = b_i$. Using the KZG opening he can decrypt the ciphertext $\mathsf{ct}_{b_i}$ to obtain $m_{b_i}$. If he could decrypt the other ciphertext $\mathsf{ct}_{1-b_i}$ he would have broken binding of the commitment.

In the paper, we observe that this simple scheme is actually very competitive with the state-of-the-art laconic OT protocols. In particular the communication complexity is very low.

Conclusion

We looked at what witness encryption is and how to construct it efficiently for the language of KZG openings. The Laconic OT scheme has been implemented and benchmarked, the code is publicly available here. If you are interested in learning more about these topics one of my co-authors gave a presentation at the study club of the Ethereum Privacy & Scaling Explorations:

{{< youtube 81Hq7Ij94vE >}}

$x$$(X - x)$$f(X) - y$
Keep reading
Latest

Optimizing Cryptography with AI

Many of us are using AI to generate code. Vibe coding cryptography is especially sensitive - you have to uphold strict mathematical correctness. This can lead to wrong security guarantees and soundness bugs. We will discuss what are some patterns to do it well.

Kobi Gurkan · August 11, 2026

Introducing zkvmBlast: Differential Fuzzing for Ethereum's zkVMs

zkVMs are moving to the center of Ethereum's roadmap, which means a bug in a zkVM is turning into a bug in Ethereum itself. We built zkvmBlast, a zkVM-agnostic differential fuzzer that runs the same program across SP1, RISC0, OpenVM, Pico, Zisk, and Airbender against a reference simulator and flags any disagreement. It hunts for both soundness and completeness bugs, with a deliberate focus on completeness, an under-explored class that can turn a single valid block into a liveness failure. We share the first batch of findings.

Stefanos Chaliasos, Martín Ochoa, Varun Thakore · August 10, 2026

Circom-Auditor: Open-Source Skills for Finding Vulnerabilities in Circom Code

We are releasing zk-skills, a set of open-source security skills for AI coding agents, starting with circom-auditor: a first line of defense against vulnerabilities in Circom circuits, compatible with both Claude Code and Codex. On the zkbugs benchmark it detects up to 66 of 70 known bugs when pointed at the vulnerable circuits, and up to 40 of 56 when let loose on the full original codebases, far ahead of existing Circom security tools.

Stefanos Chaliasos, Hao Pham, False Witness Team · August 05, 2026
Recommended

Variants of KZG: Part I, Univariate

In this blog post, we dive into the world of polynomial commitment schemes (PCS), which are crucial for constructing most practical SNARKs. We cover the basics of how PCS works, focusing on KZG10, known for its efficiency in proof size and verification time. You'll learn about the essential properties of binding and hiding and explore technical concepts like homomorphism, batching, and unconditionally hiding. We break down various methods to achieve these features, offering insight into how PCS maintains the security and privacy of polynomials in cryptographic systems. Get ready to understand these powerful concepts and their applications in modern cryptography!

Varun Thakore · April 28, 2025

𝒫𝔩𝔬𝔫𝒦: A Hands-On Deep Dive

𝒫𝔩𝔬𝔫𝒦’s many layers (selector polynomials, wiring permutations, quotient tests, random challenges and KZG commitments) can be overwhelming. Our zkSecurity tutorial uses a single running example to demystify them all. Build tables and interpolate low-degree BN254 polynomials, encode gate and wiring constraints, run deterministic and probabilistic zero-tests, then layer in randomness and KZG commitments to produce a full Fiat–Shamir proof. Grab the Jupyter Notebook (Sage or Cocalc), or work in your favorite language with our guided test cases.

Martín Ochoa · August 05, 2025

Breaking Down Bulletproofs: No Pairings, No Trusted Setup

Learn how Bulletproofs enables efficient zero-knowledge proofs without trusted setups by computing inner products in a verifiable way. This post breaks down the core folding technique that reduces large vectors to single elements through recursive compression, making proofs both compact and fast to verify. Used in Monero, Mina's Kimchi, and Zcash's Halo 2, Bulletproofs is a practical alternative to pairing-based schemes.

David Wong · October 23, 2025