Loading [MathJax]/extensions/tex2jax.js

Halo 2の中で使われている多項式コミットメントスキーム

お知らせ
Table of Contents

はじめに

この記事では、zk-SNARKのライブラリであるhalo2で使用される多項式コミットメントスキーム(Polynomial Commitment Scheme; PCS)について解説します([1]のAppendix 2)。
PCSは、名前の通り、多項式のコミットメント(特定の性質を持つ多項式を知っていたことを後で証明できるもの)を伝えるプロトコルです。
halo2の実際の実装と論文の相違点はドキュメント[3]に説明があります。

halo2のPCSとアキュムレーションスキーム

halo2のPCSは入力長の対数に比例するラウンド数でメッセージのやりとりを抑えるように構成されています。このプロトコルは、特殊な形式の内積アーギュメントを利用することで、「アキュムレータacciacc_i」を用いる、Accumulation schemes[1]を実現しています。そして、halo2ではこのAccumulation schemesを利用することでSNARKが構成されています。

アキュムレータは、証明の対象の列q1,q2q_1, q_2\cdotsにおいて、iiまでの対象が正しかったことを示すことができ、(i)その検証時間が通常のqiq_iの検証よりも短い、(ii)証明のサイズが増加しない、という二つの性質を持っています。

アキュムレーションスキームは、以下の3つのアルゴリズムによって構成されています。

  1. 証明者:新しいインスタンスとそれまでのアキュムレータから、新しいアキュムレータを作成
  2. 検証者:新しいインスタンスとそれまでのアキュムレータ、証明者によって作成されたアキュムレータの整合性を検証
  3. 決定者:証明の最後でアキュムレータに蓄積された証明が正しいかどうかを判断

つまり、アキュムレータは「証明を次々と蓄積していき、それまでの証明が正しいことと、新しい証明が正しいことを一回の計算で検証できるような証明」と言えます。内積アーギュメントを利用したアキュムレーションスキームでは多項式コミットメントを作成します。アキュムレーションスキームのアルゴリズムはそれぞれ以下の様に動作します。

  1. 証明者:ランダムオラクルを用いて得たチャレンジを利用して、新しいインスタンスとそれまでのアキュムレータから新しい多項式コミットメントを作成することで新しいアキュムレータを作成
  2. 検証者:(i)内積アーギュメントの検証、(ii)ランダムオラクルを用いて生成されたチャレンジを利用した多項式コミットメントの整合性の検証、によって新しいインスタンスとそれまでのアキュムレータの整合性を検証
  3. 決定者:証明の最後で、アキュムレータのコミットメント内の多項式を評価点での値を調べることでアキュムレータに蓄積された証明が正しいかどうかを判断

内積アーギュメントを用いたアキュムレーションスキームは、コミットメントCC、このコミットメント内の多項式pp、評価点zz、評価値vvp(z)=vp(z) = vである事を示す証明π\piからなる証明対象のインスタンスと同じフォーマット(C,z,v,π)(C, z, v, \pi)を持ちます。このアキュムレーションスキームでは、離散対数問題に基づくPCSである、PCDL\text{PC}_{DL}を用いており、PCDL\text{PC}_{DL}を用いて多項式コミットメントCCが作成されます。

過去のアキュムレータと新たなインスタンスを(C1,z1,v1,π1),(C2,z2,v2,π2)(C_1, z_1, v_1, \pi_1),(C_2, z_2, v_2, \pi_2)、この証明π1,π2\pi _1, \pi _2から復元された多項式をh1(X),h2(X)h_1(X), h_2(X)ランダムオラクルを用いて作成されたチャレンジをα\alphaとします。すると、アキュムレーションスキームで作成される新たなアキュムレータでは、π1,π2\pi _1, \pi _2から復元したコミットメントをU1,U2U_1, U_2とすると新たなコミットメントがU1+αU2U_1+\alpha U_2、対応する多項式がh1(X)+αh2(X)h_1(X)+\alpha h_2(X)となり、ランダムオラクルから得た評価点zzでの値はv=h1(z)+αh2(z)v = h_1(z)+\alpha h_2(z)となります。そして証明π\pip(z)=vp(z) = vを示すPCDL\text{PC}_{DL}OpenOpenの操作の結果となり、これらを合わせた(C,z,v,π)(C, z, v, \pi)が新たなアキュムレータとなります。

さらにhalo2では、評価点での値が0になるような、ランダムに選択した多項式を用いることで(Openの2の操作)、PCDL\text{PC}_{DL}にhidingと呼ばれる性質を持たせ、SNARKのゼロ知識性を実現しています。

本稿ではこのPCDL\text{PC}_{DL}の解説を試みます。

内積アーギュメント

以降、G\mathbb{G}を位数ppの巡回群(例えば有限体上の楕円曲線の有理点のなす群)とします。
本稿で解説するPCSで用いられる内積アーギュメントは、証明者と検証者が生成元のベクトルG,HGnG,H\in \mathbb{G}^nと生成元UGU\in \mathbb{G}を共有し証明者が予めコミットメントとして
P=Σi=0naiGi+Σi=0nbiHi+a,bU      (1)P = \Sigma _{i=0}^{n}a_i\cdot G_i +\Sigma _{i=0}^{n}b_i\cdot H_i + \braket{\vec{a},\vec{b}} \cdot U \;\;\;(1)
を伝えておき、後でこれらの内積の値を証明者が検証者にc=a,bc = \braket{\vec{a},\vec{b}}として送ると、検証者が、「証明者が、コミットメントを作成した時点で、内積の値がccとなるベクトルa,b\vec{a},\vec{b}を知っていたこと」を検証できるような、対話型のプロトコルです。

メッセージのやりとりのラウンド数が入力長の対数で抑えられるようなこのような内積アーギュメントの例として、Bulletproofs[2]があります。
詳しくは[4]の解説を参照してください。

PCSの解説

PCDL\text{PC}_{DL}の目標は以下を実現することです。

  1. 証明者が多項式ppに対するコミットメントCCを検証者に伝えておく。
  2. 後で検証者が選択した評価点zzに対して証明者がv=p(z)v=p(z)を検証者に送り返すと、検証者がコミットメントCCを利用することで証明者がCCを作成した時点で多項式ppを知っていたことが分かるが、多項式pp自体は知ることができない。

PCDL\text{PC}_{DL}

  1. Setup(証明のフォーマットから、コミットメントの公開パラメータを作成)
  2. Trim(コミットメントの公開パラメータの中から、コミットメントの作成に用いる鍵を選択)
  3. Commit(多項式から、その多項式のコミットメントを作成)
  4. Open(多項式に評価点を代入し、開示を行う)
  5. Check(Openで得られた開示とCommitで得られたコミットメントを用いて、証明者が特定の多項式を知っていたことを検証)

の5つの手順から成ります。

Setup

証明者と検証者が共同で行う操作です。
群を選択する際に用いられるセキュリティーパラメータλ\lambdaと多項式の最大の次数DDを受け取って、公開パラメータとして

  1. G\mathbb{G}、その次数qq、その群を代表する生成元GG
  2. 多項式の係数と結合される生成元G0,,GDG_0,\cdots ,G_{D}
  3. 多項式の係数を秘密にするための生成元SS
  4. 評価値と結合される生成元HH

を返します。

Trim

証明者と検証者が共同で行う操作です。
多項式の次数を表すDD以下の値ddを受け取り、Setupの結果の、多項式と結合される生成元G0,GDG_0,\cdots G_{D}の中からd+1d+1個を選び、改めてG0,GdG_0,\cdots G_{d}。と置きます。

以降SetupとTrimの操作で得られた(G,q,G,(G0,Gd),S,H)(\mathbb{G}, q, G, (G_0,\cdots G_{d}), S, H)をコミットメントキーとします。

Commit

証明者が行う操作です。
コミットメントの対象となる多項式pp、乱数ω\omegaを受け取り、ppの係数をc=(c0,cd)\vec{c} = (c_0, \cdots c_d)としたとき(つまりp(X)=Σi=0dciXip(X) = \Sigma _{i=0}^{d}c_i X^i)、内積アーギュメントのコミットメント(1)のうち、Σi=0naiGi\Sigma _{i=0}^{n}a_i\cdot G_iの項でai=ci,Gi=Gi(i=0,d)a_i = c_i, G_i = G_i(i = 0, \cdots d)とおき、多項式の係数を秘密にするために乱数ω\omegaと生成元SSの積を加えたC:=Σi=0dciGi+ωSC := \Sigma _{i=0}^{d}c_i\cdot G_i + \omega \cdot Sをコミットメントとします。

Open

証明者が行う操作です。
多項式自体は秘密に保ったまま、検証者が選んだ評価点で多項式を評価したときの評価値を伝えることで、コミットメント作成時に、多項式を知っていたことを伝えます。

検証者が選んだ評価点zzとCommitの結果、コミットを行ったときに用いた乱数ω\omegaを用いて、以下の操作を行います。

  1. 多項式ppzzを代入したv=p(z)v = p(z)を計算する。
  2. 多項式p(z)=0\overline{p}(z)=0を満たす多項式p\overline{p}と、そのコミットメントに用いる乱数ω\overline{\omega}をランダムに選ぶ(多項式の係数を秘密にするための操作)
  3. 2.で選んだp,ω\overline{p}, \overline{\omega}にCommitを行い、その結果をC\overline{C}とする。
  4. ランダムオラクルρ\rhoを用いてチャレンジα=ρ0(C,z,v,C)\alpha = \rho _0 (\overline{C}, z, v, C)を作成
  5. 開示する多項式p:=p+αpp':=p + \alpha \overline{p}を計算し、係数をΣi=0dciXi\Sigma _{i=0}^{d}c_i X^iとする(開示する多項式から元の多項式が分からない様にしている).
  6. 開示する多項式に対応するように乱数も計算しω:=ω+αω\omega ':=\omega + \alpha \overline{\omega}とする。
  7. 証明者の不正(*)を防ぐために、評価値と結合される生成元HHを変更する。Checkのときとその値を一致させるため、pp'のコミットメントから乱数に影響される項を取り除いたC:=C+αCωSC ':=C + \alpha \overline{C} - \omega ' Sをランダムオラクルの入力に与えて得た0番目のチャレンジξ0:=ρ(C,z,v)\xi _0 := \rho (C', z, v)を用いてH=ξ0HH'=\xi _0 Hと変更する。
  8. 内積アーギュメントをFiat-Shamir変換によって対話型から非対話型に変換したプロトコルによって、L,R,U,c\vec{L}, \vec{R}, U, cを作成する。
  9. 最終的な出力として手順9の結果にC,ω\overline{C}, \omega 'を加えた(L,R,U,c,C,ω)(\vec{L}, \vec{R}, U, c,\overline{C}, \omega ' )を出力する。

この出力を用いて検証者は
C+vH=Σi=0dciGi+ωS+p(z)H      (2)C + v\cdot H'= \Sigma _{i=0}^{d}c_i\cdot G_i + \omega \cdot S + p(z)\cdot H'\;\;\;(2)
の検証によって、証明者がコミットメントのCCの作成時にp(z)=vp(z) = vを満たすような多項式ppを知っていたことを検証できます。

手順8の、内積アーギュメントをFiat-Shamir変換によって対話型から非対話型に変換したプロトコルによるコミットメントの作成は以下の手順で行われます。以下、ベクトルa=(a1,an)\vec{a} = (a_1,\cdots a_n)の左半分をl(a)=(a1,an/2)l(\vec{a}) =(a_1,\cdots a_{n/2})、右半分をr(a)=(an/2+1,an)r(\vec{a})=(a_{n/2 + 1},\cdots a_{n})と表します。
まずc0:=(c0,,cd),z0:=(1,z,zd),G0:=(G0,,Gd)\vec{c}_0 := (c_0, \cdots, c_d), \vec{z}_0 := (1, z\cdots, z^d), \vec{G}_0 := (G_0, \cdots, G_d)と初期化したあと、i=1,log(d+1)i=1,\cdots \log (d+1)の順に以下の手順を繰り返します。

  1. 前の手順で作られたベクトルの半分l(Gi1),r(ci1),l(zi1)l(\vec{G}_{i-1}), r(\vec{c}_{i-1}), l(\vec{z}_{i-1})を用いたコミットメントとして
    Li:=commitl(Gi1)H(r(ci1)r(ci1),l(zi1)))=l(Gi1),r(ci1)+r(ci1),l(zi1))HL_i := commit_{l(\vec{G}_{i-1})||H'}(r(\vec{c}_{i-1})||\braket{r(\vec{c}_{i-1}),l(\vec{z}_{i-1}))}) = \braket{l(\vec{G}_{i-1}), r(\vec{c}_{i-1})} + \braket{r(\vec{c}_{i-1}),l(\vec{z}_{i-1}))} H'
    を計算する。
  2. 1と同様にr(Gi1),l(ci1),r(zi1)r(\vec{G}_{i-1}), l(\vec{c}_{i-1}), r(\vec{z}_{i-1})を用いたコミットメントとして
    Ri:=commitr(Gi1)H(l(ci1)l(ci1),r(zi1)))=r(Gi1),l(ci1)+l(ci1),r(zi1))HR_i := commit_{r(\vec{G}_{i-1})||H'}(l(\vec{c}_{i-1})||\braket{l(\vec{c}_{i-1}),r(\vec{z}_{i-1}))}) = \braket{r(\vec{G}_{i-1}), l(\vec{c}_{i-1})} + \braket{l(\vec{c}_{i-1}),r(\vec{z}_{i-1}))} H'
    を計算する。
  3. ランダムオラクルρ0\rho_0を用いてチャレンジξi:=ρ0(ξi1,Li,Ri)\xi _i := \rho _0 (\xi _{i-1}, L_{i}, R_{i})を作成
  4. 次のラウンドで用いるためのベクトルGi:=l(Gi1)+ξir(Gi1),ci:=l(ci1)+ξi1r(ci1),zi:=l(zi1)+ξir(zi1)\vec{G}_i := l(\vec{G}_{i-1}) + \xi _i\cdot r(\vec{G}_{i-1}), \vec{c}_i := l(\vec{c}_{i-1}) + \xi _i^{-1}\cdot r(\vec{c}_{i-1}), \vec{z}_i := l(\vec{z}_{i-1}) + \xi _i\cdot r(\vec{z}_{i-1})を作成

以上の手順によって、最終的にU:=Glog(d+1),c:=clog(d+1)U:=G_{\log (d+1)}, c:=c_{\log (d+1)}としてLlog(d+1),Rlog(d+1),U,c\vec{L}_{\log (d+1)}, \vec{R}_{\log (d+1)}, U, cを出力します。

ここで防いでいる証明者の不正

ここで、Openの7の操作(*)で防いでいる、証明者の不正の例を挙げます。

悪意のある証明者が知っている多項式p(X)=Σi=0dciXip(X) = \Sigma _{i=0}^{d}c_i X^iに対する本来のコミットメントC=Σi=0dciGi+ωSC = \Sigma _{i=0}^{d}c_i\cdot G_i + \omega \cdot Sの代わりに公開されている生成元HHと適当な値ttを使った偽のコミットメントC~:=Σi=0dciGi+tH+ωS\tilde{C} := \Sigma _{i=0}^{d}c_i\cdot G_i + t\cdot H + \omega \cdot Sをコミットしたとします。7の操作を行なわず、生成元HHを変更しなかった場合には、Openの操作で証明者が本来の値v=p(z)v = p(z)の代わりにv~=p(z)t\tilde{v} = p(z)-tを送ることで
C~+v~H=Σi=0dciGi+tH+ωS+(p(z)t)H=C+vH\tilde{C} + \tilde{v}\cdot H = \Sigma _{i=0}^{d}c_i\cdot G_i + t\cdot H + \omega \cdot S + (p(z)-t)\cdot H=C+v\cdot Hより、(2)が成り立つので、検証者が偽の証明を受理してしまいます。したがって悪意のある証明者の「vvを代入すると値がp(z)tp(z)-tとなるような多項式を知っていた」という偽の証明が成功します。

Check

検証者が行う操作です。
多項式の次数dd、証明者のコミットメントCC、検証者が送った評価点zzで証明者が多項式の評価を行なった値vv、Openの操作で作成したその証明(L,R,U,c,C,ω)(\vec{L}, \vec{R}, U, c,\overline{C}, \omega ' )を受け取り、以下のように非対話型の内積アーギュメントの検証を行います。
ここで、SetupとTrimの操作で得られたコミットメントキーは(G,q,G,(G0,Gd),S,H)(\mathbb{G}, q, G, (G_0,\cdots G_{d}), S, H)です。

  1. 多項式の次数ddとコミットメントキーのベクトル(G0,Gd)(G_0,\cdots G_{d})の長さが対応していること(d=(G0,Gd)1d = |(G_0,\cdots G_{d})| - 1であること)を確認する。
  2. ランダムオラクルρ0\rho _0を用いてチャレンジα=ρ0(C,z,v,C)\alpha = \rho _0 (\overline{C}, z, v, C)を復元する。(Openの手順4に対応)
  3. 同様に、pp'のコミットメントから乱数に影響される項を取り除いたC:=C+αCωSC ':=C + \alpha \overline{C} - \omega ' S、0番目のチャレンジξ0:=ρ(C,z,v)\xi _0 := \rho (C', z, v)、生成元H=ξ0HH'=\xi _0 Hを復元する。(Openの手順8に対応)
  4. 内積アーギュメントの検証を行う。C0:=C+vHC_0 := C + v\cdot H'と置き、i=1,log(d+1)i = 1, \cdots \log (d+1)に対して以下の操作を繰り返す。(Openの手順9に対応)
    • チャレンジξi:=ρ0(ξi1,Li,Ri)\xi _i := \rho _0 (\xi _{i-1}, L_{i}, R_{i})を作成する。
    • コミットメントCi:=ξ1Li+Ci1+ξiRiC_i := \xi ^{-1}L_i + C_{i-1}+ \xi _i R_iを復元する。
  5. 多項式h(X):=i=0log(d+1)1(1+ξlog(d+1)iX2i)h(X) := \prod _{i=0} ^{\log (d+1) -1} (1+ \xi _{\log (d+1)-i} X^{2^i})を定義する。
  6. 評価点としてv:=ch(z)v' := c\cdot h(z)を計算し、5で得られた最後のコミットメントClog(d+1)C_{\log (d+1)}について、Clog(d+1)=cU+vHC_{\log (d+1)}=c\cdot U + v'\cdot H'が成り立つことを検証する。
  7. 多項式h(X)h(X)ii次の係数をhih_iとおくときU=Σi=0dhiGiU = \Sigma _{i=0}^d h_i\cdot G_iが成り立つことを検証する。

Checkの簡単な解説

Checkの手順5で定義した多項式h(X):=i=0log(d+1)1(1+ξlog(d+1)iX2i)h(X) := \prod _{i=0} ^{\log (d+1) -1} (1+ \xi _{\log (d+1)-i} X^{2^i})には「その係数ベクトルとG0\vec{G}_0の内積が、Glog(d+1)\vec{G}_{\log (d+1)}と一致する」という性質を持ちます。

例えば、多項式ppが3次式、d=3,log(d+1)=2d = 3, \log (d+1) =2の場合には、
G0=(G1,G2,G3,G4)\vec{G}_0 = (G_1, G_2, G_3, G_4)
とすると、
G1=(G1,G2)+ξ1(G3,G4)=(G1+ξ1G3,G2+ξ1G4)\vec{G}_1 = (G_1, G_2)+\xi_1(G_3, G_4) = (G_1+\xi_1 G_3, G_2+\xi_1 G_4)
G2=l(G1)+ξ2r(G1)=G1+ξ2G2+ξ1G3+ξ1ξ2G4\vec{G}_2 = l(\vec{G}_1)+\xi_2r(\vec{G}_1) = G_1 + \xi_2G_2 + \xi_1G_3 + \xi_1\xi_2G_4
となります。一方、このとき
h(X):=i=01(1+ξ2iX2i)h(X) := \prod _{i=0} ^{1} (1+ \xi _{2-i} X^{2^i})
            =(1+ξ2X)(1+ξ1X2)\;\;\;\;\;\;=(1+ \xi _{2} X)(1+ \xi _{1} X^{2})
            =1+ξ2X+ξ1X2+ξ1ξ2X3\;\;\;\;\;\;=1+ \xi _{2} X+ \xi _{1} X^{2} + \xi _{1}\xi _{2} X^3
となるので、係数ベクトルを
h=(1,ξ2,ξ1,ξ1ξ2)\vec{h}=(1,\xi _{2},\xi _{1},\xi _{1}\xi _{2})とおくとG2=h,G0\vec{G}_2=\braket{\vec{h}, \vec{G}_0}が成り立ちます。

Checkの手順7ではこれを利用して、U=Glog(d+1)U = G_{\log (d+1)}h,G0=Σi=0dhiGi\braket{\vec{h}, \vec{G}_0}=\Sigma _{i=0}^d h_i\cdot G_iと一致することを検証しています。

疑問点

  • halo2のPCSで使われている内積アーギュメントはBulletproofsとよく似た形ではありますが、厳密には異なっています。この形の内積アーギュメントがアーギュメントとして成立しているのかどうかまでは確認できていません。
  • 対話型のプロトコルである、内積アーギュメントを非対話型に変換する際に、ランダムオラクルを用いたFlat-Shamir変換を行なっているようですが、この変換の正当性、安全性について理解していません。Flozen Heartと呼ばれる脆弱性とも関連しているようです。
  • このPCSは[5]で与えられている、PCSの特殊な場合となっているようです。[5]ではIPAを一般化した、Generalized Inner Product Argument (GIPA)を提唱し、GIPAをPCSへの応用しています。しかし、詳細は理解しきれていません。

参考文献

[1]Proof-Carrying Data from Accumulation Schemes
[2]Bulletproofs: Short Proofs for Confidential Transactions and More
[3]halo2 - The halo2 Book
[4]内積アーギュメント Bulletproofsについて
[5]Proofs for Inner Pairing Products and Applications

タイトルとURLをコピーしました