STARKの原理
STARKとは
STARK(Scalable Transparent ARgument of Knowledge)は証明システムの一種です。証明システムとは、ある数学的なステートメント、例えば「フィボナッチ数列の第
- Scalable: ステートメントを直接計算するのに必要な時間を
としたとき、証明の生成時間はT であり、検証時間は\mathcal{O}(T \log T) である\mathcal{O}(\log T) - Transparent: Trusted setup(信頼できる第三者による事前のセットアップ)を必要としない
- ARgument of Knowledge: ある知識を持っていることの証明ができる
Scalableは証明と検証が比較的高速で実行できることを意味します。Transparentは、zk-SNARKで必要であったtrusted setupが必要ないことを意味します。最後のArgument of Knowledgeは、単なるステートメントだけでなく、「私は〇〇という条件に当てはまる解を知っている」などの知識の所有に関するステートメントを証明することができることを意味します。
STARKとSNARKの比較
類似の証明システムである SNARK(Succinct Non-interactive ARgument of Knowledge)と比べると、trusted setup を必要とせず、健全性(偽装証明ができないこと)がハッシュ関数の安全性のみに依存するという長所があります。ハッシュ関数の安全性は量子コンピューターで破られないと信じられているため、STARKは量子耐性を持つと考えられています[1]。一方で、一般的に SNARK よりも証明のサイズが大きく検証コストが高いという短所もあります。なお SNARK について馴染みのない方は、zk-SNARKs の原理をおすすめします。
また、SNARK は任意の計算に適応できる一方、STARK は繰り返しの構造がある計算(for ループを回し続けるようなもの)でないと非効率的になってしまうという問題もあります。一方で、そのような繰り返し構造のある計算においては、STARKのほうが効率的に実行でき、またループ上限を設定せずに実行できます。
VM(仮想マシン)は状態遷移の for ループで実装されており、またループの上限は存在しません。従って STARK は VM の証明に向いており、近年 zkVM の文脈で注目を集めています。
STARKの概観
フィボナッチ数列の第
ステートメントが正しい
という問題に変換します。ここで
多項式
検証者と証明者は次のように対話を行います。
検証者はランダムな値
このように検証者が送信した値に基づいて証明者が値を送り返す証明系のことをIOP(Interactive Oracle Proofs)と呼びます。また、検証者が公開のランダムな値を証明者に送るプロトコルをPublic Coin Protocolといいます。
STARK はこのように IOP による対話式証明ですが、public coin な IOP はFiat-Shamiar 変換によって、非対話式証明に変換できます。
数学の準備
有限体と群に関して必要な予備知識を解説します。ただ群や体を初めて見る方には説明不足の部分が多いので、適宜他の記事等をご参照ください。
有限体
体とは、(ゼロ除算を除いて)四則演算が定義された集合のことです。体の集合の要素の数が有限であるとき、有限体といいます。
と定義され、
例
などと計算されます。
フェルマーの小定理
が成り立ちます(フェルマーの小定理)。
このことから
群
すなわち、
例
と、生成元を
が存在します。
Two adicity
STARKでは
STARKNETでは、
Reed Solomon Code
(
なお、今後
例
Merkle Tree Commitment
Commitmentとは大雑把にいうと、あるデータから生成された小さなデータであり、「秘匿性」と「拘束性」を持つもののことを指します。STARKにおいてはこのうち「拘束性」と呼ばれる性質が重要です。これは、データが後から改ざんされていないことを保証する性質です。データのhashを取ったものは拘束性を持ったcommitmentとみなせます。STARKではReed Solomon Codeword
また、あるleafの値がMerkle treeにcommitされていることは、Merkle rootとMerkle pathがあれば検証することができます。Merkle pathとは、そのleafからMerkle rootを計算するのに必要なHash値のことです。図は
AIR
フィボナッチ数列の
フィボナッチ数列の条件式
となります。このことは
また、フィボナッチ数列の初期条件
与えられた
定義域の拡大
Reed Solomon Codeの節で説明したように、
と書くことができます。これはつまり、
となります。この形に書き直すことのメリットは次のようになります。
いま
「正しい」
8分の7以上の
以上の説明では
境界条件
フィボナッチ数列の初期条件と終条件の式
はまだ残っていました。これらも同様に多項式の割り算の形式に変換します。第一式について
と書くことができます。同様に
これまでのまとめ
以上を総括すると、次のようなプロトコルが考えられます。
ステートメント:
あらかじめ
- 証明者は、
を計算し、[a_0, \ldots, a_{T-1}] (P(h^i) = a_i )なるi=0,\ldots, T-1 上の多項式H を求める。P(X) の定義域をP(X) 上に拡大し、G (P(x) )を各leafとするMerkle treeにcommitする。多項式x \in G ,Z_0(X):= X^T - 1 ,Z_1(X) :=X - 1 ,Z_2(X) := X - h ,Z_3(X) := X - h^{T-2} ,C_0(X) :=(P(h^2 X) - P(h X) - P(X))(X - h^{T-2})(X - h^{T-1}) ,C_1(X) := P(X) -1 ,C_2(X) := P(X) - 1 を計算し、C_3(X) := P(X) - A (D_i(X) := C_i(X)/Z_i(X) )を求め、i = 0,1,2,3 ((D_0(x), D_1(x), D_2(x), D_3(x)) )をleafとするMerkle treeにcommitする。x \in G ,P(x) のMerkle tree rootをcommitmentとして検証者に送信する。(D_0(x), D_1(x), D_2(x), D_3(x)) - 検証者は
をランダムに選び、証明者に送信する。x \in G - 証明者は
,P(x) ,P(h x) ,P(h^2 x) と、そのMerkle Pathを検証者に提出する。(D_0(x), D_1(x), D_2(x), D_3(x)) - 検証者はMerkle Pathを検証した後、
,Z_0(x):= x^T - 1 ,Z_1(x) := x - 1 ,Z_2(x) := x - h とZ_3(x) := x - h^{T-2} ,C_0(x) := C(x) = (P(h^2 x) - P(h x) - P(x))(x - h^{T-2})(x - h^{T-1}) ,C_1(x) := P(x) -1 ,C_2(x) := P(x) - 1 を計算し、C_3(x) := P(x) - A を検証する。C_i(x) \overset{?}{=} Z_i(x) D_i(x) \quad (i = 0,1,2,3) - 2~4を複数回(~10回)繰り返す。
以上の検証により、
しかしながら、このプロトコルには脆弱性があります。
というのも、前節で「正しい」
実はこれら4つの多項式のLDTは次の手順で1つにまとめることができます。
- 検証者は
をランダムに選び証明者に提出する。\alpha_0, \alpha_1, \alpha_2, \alpha_3 \in \mathbb{F}^*_p - 証明者は
に対してLDTを行う。f(X):=\alpha_0 D_0(X) + \alpha_1 D_1(X) + \alpha_2 D_2(X) + \alpha_3 D_3(X)
検証者は
FRI
FRI(Fast Reed—Solomon Interactive Oracle Proofs of Proximity)は、
基本的はアイデアは次の通りです。以下では今後のノーテーションと統一するため
検証者が証明者に乱数
いくつか注意点があります。
また検証者は証明者が正しく
以上をまとめてみましょう。commit phaseとquery phaseに別れます。
Commit phase
- 検証者は
を\beta_0, \ldots, \beta_{n-1} からランダムに選び、証明者に送信する。\mathbb{F}_p - 証明者は
の中のf_i(X) をX^2 に置き換えることでY を構成し、g_i(X, Y) を計算する。f_{i+1}(Y) := g_i(\beta_i, Y) ,f_0(X) , ...,f_1(X) をそれぞれMerkle TreeにcommitしてMerkle rootを検証者に渡す(つまり合計でf_{n-1}(X) 個のMerkle rootを渡す)。またn は定数f_{n}(x) であり、これはそのまま検証者に渡す。C
Query phase
- 検証者は
をランダムに選び、証明者に送信する。x \in G^{(0)} - 証明者は
,s_0 = x としてs_{i + 1} = s_{i}^2 を計算する。また、s_i \in G^{(i)} を満たす2点のs_{i+1} = x^2 のうち、x \in G^{(i)} とは異なる方をs_i とおく。s'_i についてi = 0, \ldots, n-1 ,f_i (s_i) とそのMerkle pathを検証者に提出する。f_i(s'_i) - 検証者は送られてきたMerkle pathを検証したのち、
についてi = 0, \ldots, n-2 がl_i(X) := \frac{f_i(s'_i) - f(s_i)}{s'_i - s_i} (X - s_i) + f_i(s_i) を満たすことを検証し、最後にl_i(\beta_i) \overset{?}{=} f_{i+1}(s_{i+1}) を検証する。l_{n-1}(\beta_{n-1})\overset{?}{=}C - 1~3を複数回(数十回ほど)繰り返す。
Fiat-Shamiar Trasform
AIRの検証も、FRIによるLDTも、証明者と検証者が対話することによって行うIOP(Interactive Oracle Proofs)でした。ただし、STARKにおけるIOPは検証者が証明者に送信する値はすべて乱数という特徴があります。このようなIOPをPublic Coin Protocolといい、Fiat-Shamiar Transformと呼ばれる変換を使って非対話式の証明に変換できることが知られています。
そもそも、検証者が乱数を送る必要があるのは、証明者が自分の都合の良い乱数を選ぶことを防ぐためです。逆に言えば、証明者が乱数の出目を調整できないことが保証されていれば、証明者自身が乱数を生成しても問題ないことを意味します。
STARKのFiat-Shamiar Trasformは、Merkle tree commitmentを証明者が使う乱数のseed値にすることで行われます。乱数を調整するためには、Merkle rootを変える必要がありますが、そのためにはMerkle treeの内容も変える必要があります。つまり、悪意のある証明者にとっては偽装証明可能なMerkle treeのleaf値を保ったまま、Merkle rootを変える必要があり、大きな計算コストが発生します。この計算コストが非常に大きく、現実的な時間内で偽装証明が可能になる確率が無視できるほど小さいとき、Fiat-Shamiar Trasformは安全であるとみなされます。
ただし、Fiat-Shamiar Trasformの不適切な実装は容易にセキュリティホールを生み出します。すでにいくつかのFiat-Shamiar Trasformを用いたアプリケーションでFrozen Heartと呼ばれる脆弱性が発見されています。
Fiat-Shamiar Trasformの実装では、乱数生成器
STARK
最終的なSTARKのプロトコルは次のようになります。これまでに定義した記号に関しては定義を省略します。また、逐次証明を作成して提出するように書いていますが、実際は最後にまとめて提出します。
証明者の手順
AIRの証明
- 多項式
,P(X) をMerkle treeにcommitし、それぞれのMerkle root(D_0(X), D_1(X), D_2(X), D_3(X)) ,\textrm{mr}_0 を提出し、\textrm{mr}_1 に登録する。\mathcal{C} \mathcal{C} \leftarrow \textrm{mr}_0, \textrm{mr}_1 - 以下の手順を
回繰り返す。l
a.x \leftarrow \mathcal{C}
b. ,P(x) ,P(h x) ,P(h^2 x) と、そのMerkle Pathを提出する。(D_0(x), D_1(x), D_2(x), D_3(x))
FRI: commit phase
\alpha_0, \alpha_1, \alpha_2, \alpha_3 \leftarrow \mathcal{C} -
を計算し、f(X) = \sum_i \alpha_i D_i(X) をMerkle treeにcommitする。そのMerkle rootf(X) を提出し、\textrm{mr}_2 に登録する。\mathcal{C} \mathcal{C} \leftarrow \textrm{mr}_2 -
,f_0(X) , ...,f_1(X) を次の手順で計算する。f_{n}(X)
a.\beta_i \leftarrow \mathcal{C}
b.f_{i+1}(Y) = g_i(\beta_i, Y) -
,f_0(X) , ...,f_1(X) をそれぞれMerkle treeにcommitする。それらのMerkle rootf_{n-1}(X) ,...,\textrm{mr}_{f_0} を提出し、\textrm{mr}_{f_{n-1}} に登録する。\mathcal{C} \mathcal{C} \leftarrow \textrm{mr}_{f_0}, \ldots, \textrm{mr}_{f_{n-1}}
また、定数 を提出し、C := f_n(X) に登録する。\mathcal{C} \mathcal{C} \leftarrow C
FRI: query phase
- 以下の手順を
繰り返す。m
a.x \leftarrow \mathcal{C}
b. とそのMerkle pathを提出する。(D_0(x), D_1(x), D_2(x), D_3(x))
c. ,...,f_0 (s_0) ,f_{n-1} (s_0) ,...,f_0 (s'_0) とそのMerkle pathを提出する。f_{n-1} (s'_0)
検証者の手順
AIRの検証
\mathcal{C} \leftarrow \textrm{mr}_0, \textrm{mr}_1 - 以下の手順を
回繰り返すl
a.x \leftarrow \mathcal{C}
b. ,P(x) ,P(h x) ,P(h^2 x) のMerkle pathを検証し、(D_0(x), D_1(x), D_2(x), D_3(x)) に対応することを確認する。x
c. (C_i (x) \overset{?}{=} D_i(x) Z_i(x) )を検証する。i = 0,1,2,3
FRIの検証
\alpha_0, \alpha_1, \alpha_2, \alpha_3 \leftarrow \mathcal{C} \mathcal{C} \leftarrow \textrm{mr}_2 \beta_0, \ldots, \beta_{n-1} \leftarrow \mathcal{C} \mathcal{C} \leftarrow \textrm{mr}_{f_0}, \ldots, \textrm{mr}_{f_{n-1}} , C - 以下の手順を
回繰り返すm
a.x \leftarrow \mathcal{C}
b. のMerkle pathを検証し、(D_0(x), D_1(x), D_2(x), D_3(x)) に対応することを確認する。x
c. を検証する。f_0(x) \overset{?}{=} \sum_i \alpha_i D_i (x)
d. (f_{i+1}(s_{i+1}) \overset{?}{=} l_i (\beta_i) )とi = 0, \ldots, n-2 を検証する。C \overset{?}{=} l_{n-1} (\beta_{n-1})
以上で非対話なSTARKを構成できました。
最後に
この記事の間違い等にお気づきになった方や、ご質問がある方は、twitterのDMまでお気軽にご連絡ください。
参考にした記事
-
STARK paper
https://eprint.iacr.org/2018/046 -
DEEP FRI paper
https://arxiv.org/abs/1903.12243 -
Vitalik's STARK post
https://vitalik.ca/general/2017/11/09/starks_part_1.html
https://vitalik.ca/general/2017/11/22/starks_part_2.html
https://vitalik.ca/general/2018/07/21/starks_part_3.html -
STARK101
https://starkware.co/stark-101/
-
SNARKは離散対数問題の困難性に安全性の根拠を持つものが多く、量子耐性を持ちません ↩︎
-
有限アーベルの基本定理からの帰結です ↩︎
-
左辺の多項式が
を根に持つことから証明できます ↩︎X = h^0,\ldots,h^{T-1} -
つまり
分母分子にC(X)/Z(X) を掛けた形 ↩︎(X - h^{T-2})(X - h^{T-1}) -
具体的には、
を適当に選びP'(X) を構成します。C'(X):=(P'(h^2 X) - P'(hX) - P'(X))(X - h^{T-2})(X - h^{T-1}) は割り切れませんが、フェルマーの小定理D'(X) := C'(X)/Z(X) よりa^{-1} = a^{p- 2} と多項式の形で書くことができます。D(X) = C'(X) (Z(X))^{p-2} を利用してX^{8T} = 1 以上の項を消去することができるので、8T は最終的に次数がD'(X) 程度の多項式になります。このように構成しても8T は成立するので、C'(X) = D'(X)Z(X) の次数を確認しない検証者は騙されてしまいます ↩︎D'(X) -
実は一般的に
個の点から定まるm 次多項式を求めるのは、高速フーリエ(逆)変換を使うとm-1 のオーダーで効率的に実行できることが知られており、今回の場合でも\mathcal{O}(m \log m) を表式通りに計算するより高速フーリエ変換のテクニックを使うほうが効率的です。ただし、説明のわかり易さのために以降もl_i(X) の表式を使って説明します。 ↩︎l_i(X)
Discussion
素晴らしい記事をありがとうございます! 以下マイナーなミスの指摘です:
巡回性の証明について
有限アーベル群の基本定理は「有限アーベル群は巡回群の積に分解できる」ことしか主張しておらず、任意の 位数q^r の巡回部分群が存在するのは \mathbb{F}_p^* 自体が巡回群であることからの帰結です。例えば \mathbb{Z}/2\mathbb{Z} \times \mathbb{Z}/2\mathbb{Z} は位数が 4 ですが、自分自身が巡回群ではなく大きさ 4 の巡回部分群も持ちません (位数 4 の要素が存在しないからです)。
ラグランジュ補間の計算量について
Fiat-Shamiar Trasform
Shamiar → Shamir です