Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

October release - IPA, IPA PCS & KZG PCS sections go live #20

Merged
merged 4 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions content/docs/zkdocs/Generic zero-knowledge systems/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
weight: 3
bookFlatSection: true
title: "Protocol primitives"
draft: true
---

# Protocol primitives

In this section we detail useful and commonly used primitives for zero-knowledge protocols.

{{<section>}}
69 changes: 69 additions & 0 deletions content/docs/zkdocs/commitments/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
weight: 9
bookFlatSection: true
title: "Commitment Schemes"
summary: "An overview of the commitment schemes and their applications"
references: ["Blum81"]
---

# Commitment Schemes Generally

Commitment schemes were introduced by Blum in 1981. Blum posed the following problem:

> Alice and Bob want to flip a coin by telephone. (They have just divorced, live in different cities, want to decide who gets the car.) Bob would not like to tell Alice HEADS and hear Alice (at the other end of the line) say "Here goes... I'm flipping the coin.... You lost!"

Blum's solution was a _commitment scheme_: a way for Bob to send his call of HEADS or TAILS ahead of time, but in a way that makes it impossible to change his mind later, and not to _reveal_ his choice until Alice has flipped the coin. Once Alice has flipped the coin, Bob can reveal his call to Alice to see who won the coin toss.

A commitment scheme has two phases:

- A _commit_ phase, in which the committer generates the commitment value and shares it with others, and

- An _open_ phase, when the committer reveals the committed value, and the commitment is verified by others

It's very important that Bob can't cheat Alice by revealing a fake call. It's also very important that Alice can't gain any information about Bob's call from his commitment. These are the two major features of a good commitment scheme:

- _Hiding_: a commitment doesn't reveal anything about the committed value

- _Binding_: it is not feasible to find two or more distinct values with the same commitment

Informally, you can think of hiding as what keeps Alice from cheating (since she can't get any information about Bob's call to use against him), and binding as what keeps Bob from cheating (since he can't "change his mind" and send a valid opening for $call'\neq call$ if Alice announces a coin toss result he doesn't like).

Lots of cryptographic protocols rely on this sort of exchange. For instance, this type of behavior is used in threshold signature schemes to allow a group of parties to securely generate an unbiased, uniformly random signing key.

To see an example of how this might be done using cryptography, consider the following process. Bob randomly selects $\sampleGeneric{call}{\{\coinheads,\cointails\}}$ as his call. Then he selects a 256-bit random value $r$ and computes, $c=\hmac{r}{call}$, then sends $c$ to Alice. Alice flips her coin, and announces either $\coinheads$ or $\cointails$. Bob then sends Alice $\left(r,call\right)$. Alice verifies that $c=\hmac{r}{call}$. If the two match, she accepts Bob's call as valid; otherwise, she rejects Bob's call as invalid.

We call $c$ Bobs's _commitment_ to his call, and we call $\left(r,call\right)$ the _opening_ of $c$.

In protocol terms, we have:

{{< rawhtml >}}
$$
\begin{array}{c}
\work{\varalice}{\varbob}
\bobwork{\sampleGeneric{call}{\{\coinheads, \cointails\}}}
\bobwork{\sampleGeneric{r}{\{0, 1\}^{256}}}
\bobwork{c_{A}=\hmac{r}{call}}
\bobalice{}{c_{A}}{}
\alicework{\sampleGeneric{toss}{\{\coinheads, \cointails\}}}
\alicebob{}{toss}{}
\bobalice{}{\left(call,r\right)}{}
\alicework{\hmac{r}{call}\equalQ c_{A} }
\end{array}
$$
{{< /rawhtml >}}

It's worth noting that simply setting $C=\hash{call}$ is problematic as a commitment mechanism. In our example, it would be trivial for Alice to compute $c_{\coinheads}=\hash{\coinheads}$ and $c_{\cointails}=\hash{\cointails}$ and compare them to Bob's value for $C$.

Similarly, in our $\mathsf{HMAC}$ scheme, if Bob doesn't select a fresh $r$ for each commitment, Alice can detect when Bob commits to the same value in different contexts.

Of course, the $\mathsf{HMAC}$ scheme isn't limited to simple $\coinheads/\cointails$ calls; it can be used for an arbitrary message $m$: $c=\hmac{r}{m}$.

This scheme will be both _hiding_ and _binding_ due to the properties of the $\mathsf{HMAC}$ function. Without $r$, Alice has no way of checking if $c$ commits to $\coinheads$ or $\cointails$, and it's computationally infeasible for Bob to find $r'$ such that $c=\hmac{r'}{call'}$ (where $call'\neq call$).

It's possible to create a commitment scheme that is hiding but not binding. Suppose the commitment $c\_{A}$ above only included the lowest 16 bits of the HMAC output. It would take a fraction of a second for Bob to find $r'\neq r$ such that $c=\hmac{r'}{call'}$.

Conversely, it's possible to have a commitment scheme that is binding but not hiding. The easiest example would be for Bob to simply send $call$ to Alice, as in the original, insecure coin flip protocol. Bob can't change his mind after sending $c$, but nothing is hidden from Alice.

Some specialized commitment schemes provide features beyond simple binding and hiding. The KZG polynomial commitment scheme, for instance, enables Bob to commit to a polynomial $f$ while allowing him to prove that a pair $\left(x, y=f\left(x\right)\right)$ represents a correct evaluation of $f$.

{{<section>}}
199 changes: 199 additions & 0 deletions content/docs/zkdocs/commitments/ipa-pcs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
---
weight: 11
bookFlatSection: true
title: "IPA Polynomial Commitment"
summary: "An overview of the Inner Product Argument polynomial commitment scheme"
needsVariableResetButton: true
references: ["Bootleproofs", "Bulletproofs", "Halo", "ProofCarryingData", "Halo2"]
---

# IPA Polynomial Commitment

## Overview of IPA Polynomial Commitment

The inner product argument was introduced by Bootle et al. {{< cite Bootleproofs >}}, and refined in Bulletproofs {{< cite Bulletproofs >}}. This protocol was specialized to polynomial commitments in {{< cite Halo >}} then further studied and refined in {{< cite ProofCarryingData >}}.

{{< hint info >}}
**Goal:**
$\varprover$ convinces $\varverifier$ that they know a secret polynomial $\varf$ such that $\varf(\varx) = \varv$, for evaluation point $\varx$ and evaluation $\varv$; and this satisfies the polynomial commitment $\varC_{\varP}$.
{{< /hint >}}

* __Public input:__ a cyclic additive group $\cgroup$ of prime order $\varq$ and $n+1$ random $\cgroup$ generators $\vecG = (\varG_1,\dots,\varG_n)$ and $\varH$; polynomial commitment $\varC_{\varP} \in \cgroup$, scalar $\varx \in \zq$, and scalar $\varv \in \zq$.

* __Private input:__ $\varprover$ knows secret polynomial $\varf$ that satisfies the polynomial commitment $\varC_P$ and $\varf(\varx) = \varv$.

**Comparison with [KZG Polynomial Commitments]({{< ref "./kzg_polynomial_commitment" >}}).**
IPA PCS requires fewer assumptions but is less efficient. IPA does not require a trusted setup and only assumes discrete log, whereas KZG requires a trusted setup and assumes pairings. But, IPA proofs are $O(\log \varn)$ and the verifier needs to do $O(n)$ work, whereas KZG proofs are $O(1)$ and the verifier only needs to do $O(1)$ work. That said, the verification time for IPA proofs can be amortized over multiple runs.

## Polynomial Commitment from IPA

In this section, we build polynomial commitments from IPA over two successive versions.

### Version 1: A Simple, Non-Hiding Construction

The most straightforward way to do polynomial commitments is to interpret the polynomial $f(\varX) = \vara_1 + \vara_2 \varX + \vara_3 \varX^2 + \cdots + \vara_{\varn} \varX^{\varn-1}$ as a vector of coefficients $(a_1,\dots,a_{\varn})$ and fix the other vector to be powers of the evaluation point $\vecb = (1, \varx, \varx^2, \dots, \varx^{\varn-1})$. Then their inner product
$$
\ip{\veca}{\vecb} = \vara_1 + \vara_2 \varx + \vara_3 \varx^2 + \cdots + \vara_{\varn} \varx^{\varn-1}
$$
is the evaluation $f(x)$.

Since $\vecb$ is now public, the prover no longer has to commit to it. So, the verifier can compute the reduced value $\vecb_{\varm}$ similar to how it computes $\vecG_{\varm}$ in the Inner Product Argument using the polynomial $\varg(\varX) \coloneqq \prod_{i=0}^{\varm-1} (1 + \varu_{\varm-i} \varX^{2^i})$:
$$
\begin{align}
\vecG_{\varm} &= \varG_1 + \varu_{\varm} \varG_2 + \cdots + \varu_1 \varu_2 \cdots \varu_{\varm} \cdot \varG_n = \ip{\vecg}{\vecG}\\\\
\vecb_{\varm} &= 1 + \varu_{\varm} \varx + \cdots + \varu_1 \varu_2 \cdots \varu_{\varm} \cdot \varx^{\varn-1} = \ip{\vecg}{\vecb}\\\\
\end{align}
$$

The full protocol, adapted from Version 4 in [Inner Product Argument]({{< ref "./../zero-knowledge-protocols/ipa/_index.md" >}}) is as follows:

{{< rawhtml >}}
$$
\begin{array}{lcl}
\uwork{\varprover}{\varverifier}
\aliceworks{\veca \coloneqq (\vara_1,\dots,\vara_{\varn})}
\dupwork{\vecb \coloneqq (1, \varx, \varx^2, \dots, \varx^{\varn-1})}
\aliceworks{\varC_P \coloneqq \ip{\veca}{\vecG}}
\aliceworks{\varU \coloneqq \hashtogroup{\vecG, \varx, \varv, \varC_P}}
\aliceworks{\varC_0 \coloneqq \varC_P + \ip{\veca}{\vecb} \cdot \varU}
\aliceworks{\ctx \gets (\vecG, \varx, \varv, \varC_P, \varU, \varC_0)}
\aliceworks{\veca_0 \coloneqq \veca;\; \vecb_0 \coloneqq \vecb;\; \vecG_0 \coloneqq \vecG}
\aliceworks{\text{For $i \coloneqq 1$ to $\varm$:}}
\aliceworks{\indent \varL_i \coloneqq \ip{\veca_{i-1,R}}{\vecG_{i-1,L}} + \ip{\veca_{i-1,R}}{\vecb_{i-1,L}} \cdot \varU}
\aliceworks{\indent \varR_i \coloneqq \ip{\veca_{i-1,L}}{\vecG_{i-1,R}} + \ip{\veca_{i-1,L}}{\vecb_{i-1,R}} \cdot \varU}
\aliceworks{\indent \ctx.\append(\varL_i, \varR_i)}
\aliceworks{\indent \varu_i \coloneqq \hashtofield{\ctx}}
\aliceworks{\indent \vecG_i \coloneqq \vecG_{i-1, L} + \varu_i \cdot \vecG_{i-1,R}}
\aliceworks{\indent \veca_i \coloneqq \veca_{i-1,L} + \varu_i^{-1} \cdot \veca_{i-1,R}}
\aliceworks{\indent \vecb_i \coloneqq \vecb_{i-1,L} + \varu_i \cdot \vecb_{i-1,R}}
\alicebob{}{\varC_P, (\varL_1,\varR_1),\dots,(\varL_{\varm}, \varR_{\varm})}{}
\alicebob{}{\veca_{\varm}}{}
\bobworks{\varU \coloneqq \hashtogroup{\vecG, \varx, \varv, \varC_P}}
\bobworks{\varC_0 \coloneqq \varC_P + \varv \cdot \varU}
\bobworks{\ctx \gets (\vecG, \varx, \varv, \varC_P, \varU, \varC_0)}
\bobworks{\text{For $i \coloneqq 1$ to $\varm$:}}
\bobworks{\indent \ctx.\append(\varL_i, \varR_i)}
\bobworks{\indent \varu_i \coloneqq \hashtofield{\ctx}}
\bobworks{\indent \varC_{i} \coloneqq \varu_{i}^{-1} \cdot \varL_{i} + \varC_{i-1} + \varu_{i} \cdot \varR_{i}}
\bobworks{\vecg \coloneqq \varg(X) \coloneqq \prod_{i=0}^{m-1} (1 + \varu_{m-i} X^{2^i})}
\bobworks{\vecG_{\varm} \coloneqq \ip{\vecg}{\vecG}}
\bobworks{\vecb_{\varm} \coloneqq \ip{\vecg}{\vecb}}
\bobworks{\varC_{\varm} \equalQ \ip{\veca_{\varm}}{\vecG_{\varm}} + \ip{\veca_{\varm}}{\vecb_{\varm}} \cdot \varU}
\end{array}
$$
{{< /rawhtml >}}

{{< hint warning >}}
**This construction is not hiding.** This construction reveals $\veca_{\varm}$ which in turns leaks at least one bit of information about $\veca = \varf$.
{{< /hint >}}

{{< hint info >}}
**Amortization.** The computation of $\vecG_{\varm}$ and $\vecb_{\varm}$ (the only linear time computations the verifier needs to do) can be amortized over multiple runs, see "Amortization" in [Inner Product Argument]({{< ref "./../zero-knowledge-protocols/ipa/_index.md" >}}) for details.
{{< /hint >}}

### Version 2: Hiding Construction

Version 1 did not hide the polynomial $\varf$ and thus was not zero-knowledge. This version remedies that by using hiding commitments and an intermediate random-looking polynomial.

First, we compute a hiding commitment $\varC_P$ to the polynomial $\varf$. Let $\veca$ and $\vecb$ be the coefficients of $\varf$ and powers of the evaluation point $\varx$, respectively, as before. The prover samples a random blinding factor $\sample{\vart}$ and computes
$$
\varC_P \coloneqq \ip{\veca}{\vecG} + \vart \cdot \varH
$$

Second, we compute a random-looking polynomial. Sample a random polynomial $p_r(\varX) \coloneqq \vars_1 + \vars_2 \varX + \vars_3 \varX^2 + \cdots + \vars_{\varn} \varX^{\varn-1}$ of the same degree as $\varf$ by picking random coefficients $\vars_1,\dots,\vars_{\varn}$. Construct $\bar{\varf} \coloneqq p_r - p_r(\varx)$ so that $\bar{\varf}$ looks random and has a root at the evaluation point $\varx$; that is, $\bar{\varf}(\varx) = 0$.

Third, we compute a hiding commitment to the random-looking polynomial. Let $\bar{\veca} \coloneqq (\varw_{1},\dots,\varw_{\varn})$ be the coefficients of $\bar{\varf}$. The prover samples a random blinding factor $\sample{\bar{\vart}}$ and computes the commitment
$$
\bar{\varC}_P \coloneqq \ip{\bar{\veca}}{\vecG} + \bar{\vart} \cdot \varH
$$

Fourth, we blind the polynomial $\varf$ using the random-looking polynomial $\bar{\varf}$. After receiving these commitments, the verifier samples some randomness $\varalpha$ and the prover uses it to compute the blinded polynomial $\varf' \coloneqq \varf + \varalpha \cdot \bar{\varf}$. Let $\vecc = (\varc_1,\dots,\varc_n)$ be the coefficients of $\varf'$. The prover computes the corresponding randomness $\vart' \coloneqq \vart + \varalpha \cdot \bar{\vart}$ and uses it to compute a non-hiding commitment to $\varf'$ as $\varC_P' \coloneqq \varC_P + \varalpha \cdot \bar{\varC}_P - \vart' \cdot \varH = \ip{\vecc}{\vecG}$.

Now we continue with the halving like Version 1, except using the blinded polynomial $\varf'$ in place of the original polynomial $\varf$. The full protocol is below.

{{< rawhtml >}}
$$
\begin{array}{lcl}
\uwork{\varprover}{\varverifier}
\aliceworks{\veca \coloneqq (\vara_1,\dots,\vara_{\varn})}
\dupwork{\vecb \coloneqq (1, \varx, \varx^2, \dots, \varx^{\varn-1})}
\aliceworks{\sample{\vart}}
\aliceworks{\varC_P \coloneqq \ip{\veca}{\vecG} + \vart \cdot \varH}
\aliceworks{\sampleGeneric{\varp_r}{\zq^{\varn}}}
\aliceworks{\bar{\varf} \coloneqq \varp_r - \varp_r(\varx)}
\aliceworks{\bar{\veca} \coloneqq (\varw_1,\dots,\varw_n) = \bar{\varf}}
\aliceworks{\sample{\bar{\vart}}}
\aliceworks{\bar{\varC}_P \coloneqq \ip{\bar{\veca}}{\vecG} + \bar{\vart} \cdot \varH}
\aliceworks{\ctx \gets (\vecG, \varH, \varx, \varv, \varC_P, \bar{\varC}_P)}
\aliceworks{\varalpha \coloneqq \hashtofield{\ctx}}
\aliceworks{\vecc \coloneqq \veca + \alpha \cdot \bar{\veca} = \varf'}
\aliceworks{\vart' \coloneqq \vart + \varalpha \cdot \bar{\vart}}
\aliceworks{\varC_P' \coloneqq \varC_P + \varalpha \cdot \bar{\varC}_P - \vart' \cdot \varH = \ip{\vecc}{\vecG}}
\aliceworks{\ctx.\append(\varC_P')}
\aliceworks{\varU \coloneqq \hashtogroup{\ctx}}
\aliceworks{\varC_0 \coloneqq \varC_P + \ip{\veca}{\vecb} \cdot \varU}
\aliceworks{\ctx.\append(\varC_0)}
\aliceworks{\vecc_0 \coloneqq \vecc;\; \vecb_0 \coloneqq \vecb;\; \vecG_0 \coloneqq \vecG}
\aliceworks{\text{For $i \coloneqq 1$ to $\varm$:}}
\aliceworks{\indent \varL_i \coloneqq \ip{\veca_{i-1,R}}{\vecG_{i-1,L}} + \ip{\veca_{i-1,R}}{\vecb_{i-1,L}} \cdot \varU}
\aliceworks{\indent \varR_i \coloneqq \ip{\veca_{i-1,L}}{\vecG_{i-1,R}} + \ip{\veca_{i-1,L}}{\vecb_{i-1,R}} \cdot \varU}
\aliceworks{\indent \ctx.\append(\varL_i, \varR_i)}
\aliceworks{\indent \varu_i \coloneqq \hashtofield{\ctx}}
\aliceworks{\indent \vecG_i \coloneqq \vecG_{i-1, L} + \varu_i \cdot \vecG_{i-1,R}}
\aliceworks{\indent \vecc_i \coloneqq \vecc_{i-1,L} + \varu_i^{-1} \cdot \vecc_{i-1,R}}
\aliceworks{\indent \vecb_i \coloneqq \vecb_{i-1,L} + \varu_i \cdot \vecb_{i-1,R}}
\alicebob{}{\varC_P, (\varL_1,\varR_1),\dots,(\varL_{\varm}, \varR_{\varm})}{}
\alicebob{}{\bar{\varC}_P, \veca_{\varm}, \vart'}{}
\bobworks{\varv \mod \varq \gQ 0}
\bobworks{\varx \mod \varq \gQ 0}
\bobworks{\vart' \mod \varq \gQ 0}
\bobworks{\varC_P \neq 0 \text{ (point at infinity for EC groups)}}
\bobworks{\varC_P \inQ \cgroup \text{ (on curve check for EC groups)}}
\bobworks{\bar{\varC}_P \neq 0 \text{ (point at infinity for EC groups)}}
\bobworks{\bar{\varC}_P \inQ \cgroup \text{ (on curve check for EC groups)}}
\bobworks{\varL_i, \varR_i \neq 0 \text{ (point at infinity for EC groups)}}
\bobworks{\varL_i, \varR_i \inQ \cgroup \text{ (on curve check for EC groups)}}
\bobworks{\vara_i \mod \varq \neq 0}
\bobwork{\text{ for }i=1,\ldots,m}
\bobseparator
\bobworks{\ctx \gets (\vecG, \varH, \varx, \varv, \varC_P, \bar{\varC}_P)}
\bobworks{\varalpha \coloneqq \hashtofield{\ctx}}
\bobworks{\varC_P' \coloneqq \varC_P + \varalpha \cdot \bar{\varC}_P - \vart' \cdot \varH}
\bobworks{\ctx.\append(\varC_P')}
\bobworks{\varU \coloneqq \hashtogroup{\ctx}}
\bobworks{\varC_0 \coloneqq \varC' + \varv \cdot \varU}
\bobworks{\ctx.\append(\varC_0)}
\bobworks{\text{For $i \coloneqq 1$ to $\varm$:}}
\bobworks{\indent \ctx.\append(\varL_i, \varR_i)}
\bobworks{\indent \varu_i \coloneqq \hashtofield{\ctx}}
\bobworks{\indent \varC_{i} \coloneqq \varu_{i}^{-1} \cdot \varL_{i} + \varC_{i-1} + \varu_{i} \cdot \varR_{i}}
\bobworks{\vecg \coloneqq \varg(X) \coloneqq \prod_{i=0}^{m-1} (1 + \varu_{m-i} X^{2^i})}
\bobworks{\vecG_{\varm} \coloneqq \ip{\vecg}{\vecG}}
\bobworks{\vecb_{\varm} \coloneqq \ip{\vecg}{\vecb}}
\bobworks{\varC_{\varm} \equalQ \ip{\veca_{\varm}}{\vecG_{\varm}} + \ip{\veca_{\varm}}{\vecb_{\varm}} \cdot \varU}
\end{array}
$$
{{< /rawhtml >}}

{{< hint info >}}
**Comparison with [[BCMS20]](https://eprint.iacr.org/2020/499).** Rather than compute $\varU \coloneqq \xi_0 \cdot \varH$ using a challenge field element $\xi_0$, we directly ask for the challenge group element $\varU$. These approaches are equivalent.
{{< /hint >}}

{{< hint info >}}
**Comparison with [[BGH19]](https://eprint.iacr.org/2019/1021).** Rather than run halving with the original polynomial and blind the outputs, $\varL_i$, $\varR_i$, and $\veca_{\varm}$, we instead run halving with a blinded polynomial $\bar{\varf}$.
{{< /hint >}}

This construction has perfect completeness and, as outlined above, computational soundness. See Appendix A.3 of {{< cite ProofCarryingData >}} for a proof.

## Security Assumptions

* **Discrete logarithm:** The security of this protocol relies on the hardness of discrete logarithm in the group $\cgroup$. Specifically, it assumes that there are no known discrete log relations between the random generators. Concretely, for 128-bit security consider elliptic curve groups of size greater than $2^{256}$.

## Security Pitfalls
* **Verifier input validation:** Each of the items above the dotted line for the $\varverifier$ is essential to the security of the protocol. If any of these checks are missing or insufficient it is likely a severe security issue.
* **Weak Fiat-Shamir transform:** When transforming the interactive protocol into a non-interactive protocol with the Fiat-Shamir transform, care needs to be taken to ensure that all parameters are included in the hash. See [Fiat-Shamir transformation]({{< ref "./../protocol-primitives/fiat-shamir.md" >}}).
* **Replay attacks:** This construction does not provide replay protection; i.e., proofs can be replayed. But, replay protection can be achieved by adding more information to the $\Hash$ invocations, see [Preventing replay attacks]({{< ref "./../protocol-primitives/fiat-shamir.md#preventing-replay-attacks" >}}).
* **Verifier trusting the prover:** All version of this protocol assume that the verifier does not trust the prover beyond the protocol. See the warning in Section 2 of [Inner Product Argument]({{< ref "./../zero-knowledge-protocols/ipa/_index.md" >}}).

## See also
- {{< section_entry "docs/zkdocs/zero-knowledge-protocols/ipa" >}}
Loading
Loading