# EPF Week 7 Update 8 & 9
After going through [Dankrad's IPA note with Pedersen](https://dankradfeist.de/ethereum/2021/07/27/inner-product-arguments.html) and then going through a few more [resources on IPA](https://www.youtube.com/watch?v=RaEs5mnXIhY&t=1582s&pp=ygUXaW5uZXIgcHJvZHVjdCBhcmd1bWVudHM%3D). I finally realised how IPA multipoint really worked!
### Intro
Here I'll talk about how we can open multiple polynomials at different points.
Finally aggregating to 1 proof, 1 commitment and 1 scalar.
### Definition
Given $m$ IPA commitments $C_0 = [f_0(X)] ... C_{m-1} = [f_{m-1}(X)]$, prove evaluations:
$$
f_0(z_0) = y_0 \\\vdots \\f_{m-1}(z_{m-1}) = y_{m-1}
$$
where $z_i \in \{0,...,d-1\}$
### Prover
1. Let $r \leftarrow H(C_0,...C_{m-1}, z_0, ..., z_{m-1}, y_0, ..., y_{m-1})$
$$
g(X) = r^0 \frac{f_0(X) - y_0}{X-z_0} + r^1 \frac{f_1(X) - y_1}{X-z_1} + \ldots +r^{m-1} \frac{f_{m-1}(X) - y_{m-1}}{X-z_{m-1}}
$$
The prover initially commits to $g(X)$, we denote this by $D$ or $[g(X)]$.
Now the prover has to convince the verifier that $D$ is a commitment to $g(X)$. We do this by evaluating $g(X)$ at some random point $t$.
We can split the evaluation into $g_1(t)$ and $g_2(t)$, $g_2(t)$. These two can be computed by the verifier, while $g_1(t)$ cannot, because it involves random evaluations at the polynomials $f_i(X)$.
Hence the verifier is able to compute $g_2(t)$, and the prover will compute $g_1(t)$ and send a proof of it's correctness.
The expressions are as following:
$$
g_1(t) = \sum_{i=0}^{m-1} r^i \frac{f_i(t)}{t-z_i}
$$
$$
g_2(t) = \sum_{i=0}^{m-1} r^i \frac{y_i}{t-z_i}
$$
2. Let $t \leftarrow H(r,D)$
We note that $g_1(X) = \sum_{i=0}^{m-1} r^i \frac{f_i(X)}{X-z_i}$. However, we specify it as $\sum_{i=0}^{m-1} r^i \frac{f_i(X)}{t-z_i}$ because $g_1(t)$ is also able to prove for an opening, hence the verifier is able to compute the commitment for it.
Thereby, we finally boil down to 2 IPA proofs. One for $g_1(X)$ at $t$. We call this $\pi$. And the other one for $g(X)$ at $t$. We call this $\rho$.
Hence, the prover now computes $y = g_1(t)$, and the proof consists of $D, (\pi, y), \rho$.
However, this is still the variant where we haven't yet *aggregated* the proofs.
### Verifier
The Verifier ultimately wants to verify that $D$ is the commitment to the polynomial $g(x)$, hence he computes $r$ and $t$.
Then the verifier also computes $g_2(t)$, by themselves.
However, the verifier cannot assert to the fact that $g_1(t)$ is the correct computation by the prover. The verifier has to separately build $[g_1(X)]$ and then re-check it with $g_1(t)$.
The verifier proceeds with computing $[g_1(X)]$. The verifier as I said, is able to compute this by themselves, to cross check it with $g_1(t)$ using the `ipa_verify()` function, the reference Go [implementation](https://github.com/crate-crypto/go-ipa/blob/master/ipa/verifier.go#L14-#L93), using ($[g_1(X)]$,$g_1(t)$,$\pi$) params.
As $g(t) = g_1(t) - g_2(t)$, now that since $g_1(t)$ was verified to be correct and $g_2(t)$ was computed by the verifier, we can be sure that $g(t)$ is correct.
#### Verifying $g(x)$ at $t$
We now call `ipa_verify()` passing ($D = [g(X)]*$,$g(t)$,$\rho$) as params.
Now we have 2 IPA proofs, 1 commitment and 1 scalar.
Now we are left with `aggregation` to 1 final IPA proof.
### Aggregating...
#### Prover's side
Let $q \leftarrow H(t, [g_1(X)])$
The prover no longer computes an IPA proof for $g_1(X)$ and $g(X)$ instead they combine them using $q$.
$g_3(X) = g_1(X) + q \cdot g(X)$
Now we form an IPA Proof for $g_3(X)$ at $t$. Lets call this $\sigma$.
The prover still computes $y = g_1(t)$
The proof consists of $D, \sigma, y$
#### Verifier's side
In the previous step, the verifier called $[g_1(X)]$ ,$g_1(t)$ with $\pi$, we delay this verification and instead compute:
- $[g_3(X)] = [g_1(X)] + q \cdot [g(X)]$
- $g_3(t) = g_1(t) + q \cdot g(t)$
We now call `ipa_verify()` using ($[g_3(X)]$,$g_3(t)$,$\sigma$).
This strategy finally boils down the proof to 1 IPA proof, 1 commitment and 1 scalar.