Week 2 さらなる暗号技術とSNARKsとSTARKs
CircomのTIPS
コーディング
template
: 回路のテンプレート。インスタンス化されることで回路のオブジェクトになる。
include
: 外部のテンプレートをインポートする。
component
: テンプレートをインスタンス化する。
signal input
: テンプレートに入力される値。
signal output
: テンプレートから出力される値。
signal
: signal input
の値によって変化する変数を定義する。
var
: signal input
の値によって変化しない変数を定義する。
<--
: シグナルに代入する。
<==
: シグナルに代入しつつ、両辺が等しいという制約をR1CSに追加する。基本的に <--
ではなくこちらの使用が推奨される。
Circom特有の注意点
ハッシュ関数
circomでは値を有限体の算術回路として計算するため、ビット演算では制約が増加し、通常よりも計算量が増えます。これは使用するハッシュ関数の選定時にも重要な点で、Solidityでも使用されるkeccak-256はビット演算のため、Circomでは扱いづらいです。
そのためCircomでは有限体上で計算する以下のようなハッシュ関数が好まれます。
Poseidon: zkSNARKで最も効率的に動作。回路内での成約数を最小限に抑える設計。
MiMC: zkSNARKで効率的に動作。ラウンド数等のパラメータを選択できる。
Pedersen: 楕円曲線を使用したPedersenコミットメントに基づく。加法準同型性を持つ。
zkSNARKでは、特にPoseidonハッシュがよく利用されます。
分岐とループ
Circomのコードは算術回路などに変換された後、証明者と検証者に渡されるため、証明者から入力される signal input
によって算術回路の構造を後からダイナミックに変化させることはできません。
つまり、分岐やループの条件部分など、算術回路の構造に影響を与えるような部分のCircomのコードでは、 signal
の値を直接利用することができません。
例えば、if文で signal
の値により分岐させたい場合には、どちらの分岐も計算され両方の和が計算されるものの、条件により分岐の片方の計算結果は0になるようにコードを書く必要があります。
これを実現するために、以下の2つの段階が必要です。
分岐ごとに、
signal
と比較する値が入力され、それぞれに対して0か1が出力される前述の出力(0か1の値)と各分岐の計算結果が入力され、計算結果と前述の出力の組のどちらかの積が0となり2組の和が計算されるように出力される
前者には IsEqual
や LessThan
等のテンプレートがあり、後者はシンプルな分岐の場合には容易に自身で書くこともできますが、 Mux1
テンプレート等が利用できます。
Tornado Cash
Tornado Cashは、ZKによってプライバシーを保護した送金を可能にする分散型プロトコルです。
旧バージョンのTornado Cash Classicと2021年リリースのTornado Cash Novaの2種類があります。
概要(ClassicとNovaに共通)
送金するETHアドレス(Alice)と受け取るETHアドレス(Bob)の間のオンチェーン上での関係性を、第三者に分からないようにすることで、プライバシー送金を実現します。
具体的には、AliceがBobに直接送金するのではなく、Aliceがプールコントラクトに入金し、Bobがプールコントラクトから出金します。
プールコントラクトの利用者がAliceとBob以外にも多く存在し、かつ各入出金ペアの関係性が分からないとき、プライバシーを保つことができます。(ミキシング)
この状況下で、Aliceが入金したトークンをBobが出金できるようにするために、ZK(zkSNARKであるGroth16)とマークルツリーを使用しています。
Classicの特徴
Classicでは、各入金に対して秘密の文字列(プライベートノート)を生成し、出金時にそれを入力させることで、正しい出金者かを検証します。
このプライベートノートの検証にZKを使うことで、チェーン上のプールコントラクトで送金者を検証できます。
しかし、以下のような欠点もあります。
何らかの安全な方法でプライベートノートを出金者に伝える必要がある
出金のタイミングや金額を他の利用者とある程度合わせなければ、ミキシングの効果が薄れてしまう
Novaの特徴
ここでは、Classicからのいくつかの変更のうち、ミキシングに関連する部分を解説します。
Novaでは上記のようなClassicの欠点を改善するために、プライベートノートではなく、各ユーザーのアカウントごとの残高と直前の入出金額の記録(アカウントベースのUTXO)を、入出金の度に更新していくように変更されました。
AliceからBobにプライベート送金をしたい場合には、以下のフローに従います。
AliceとBobが秘密鍵を生成し、公開鍵をコントラクトに送る(アカウント作成)
Aliceは自身の秘密鍵とAliceとBobのUTXO(初回は残高0)等から、UTXOの金額等を検証するためのZKの証明を作成し、プールコントラクト上で検証と入金を行う
BobはAliceが入金したときと類似の方法(秘密鍵とUTXOの証明)で出金する
この変更により、プールコントラクト上でアカウントベースで資金を記録できるようになり、出金額を入金額と異なる金額に設定可能になったため、ミキシングの効果が高まり、より自由度の高い取引が実現しました。
リレーヤーの役割
ここまでは、ユーザーのクライアント上での秘匿化とそれがコントラクトでどのように検証・入出金されるかを確認してきました。
しかし、まだ出金側のアドレスに出金のトランザクションを実行するためのガス代が必要になるという問題があります。つまり匿名送金を受け取りたいのに、そのためには匿名ではない資金が必要になってしまうという矛盾が発生することになります。
これを解決するために、ユーザーはリレーヤーにトランザクションの実行を代理するように依頼できます。
リレーヤーは出金のトランザクション時にその金額の一部を手数料として受け取ることができます。
STARKs
以下のvitalik氏の記事を自分なりに解釈したものとなっています。 vitalik氏の記事から拝借している図もあります。ご了承ください。
https://vitalik.eth.limo/general/2017/11/09/starks_part_1.html
https://vitalik.eth.limo/general/2017/11/22/starks_part_2.html
概要
zkSNARKsは検証可能な計算やプライバシー保護型暗号通貨など、さまざまな用途に使用できる汎用の簡潔なゼロ知識証明技術である。zkSTARKsの「T」は透明性(Transparent)を意味し、zkSNARKsの課題であったTrusted Setupへの依存を解消している。また、楕円曲線やペアリング、KEAを必要とせず、ハッシュと情報理論に基づいている。これにより、量子コンピュータを持つ攻撃者に対しても安全である。
STARKs, Part I: Proofs with Polynomials
「ある多項式を知っている」ことを証明したいとする。ここでは例としてとは以下の性質を満たすと仮定する。
単純な証明を考えると、点全てでを確認する方法が考えられる。しかし、これは大変なのでランダムな点で検証する方法が考えられる。しかしこれもまた、サンプリングしたランダムな点において偶然と一致していたが検証を通過してしまうという問題がある。
問題の変換
まず、制約チェック多項式を導入する。は以下の性質を満たす。
ここで、「多項式を知っている」という問題は「なるを知っている」という問題に変換される。
次に、はを根に持つため、は多項式で割り切れるという事実を用いると、
「なるを知っている」という問題は、「なるとを知っている」という問題に変換される。はをで多項式除算すれば求まる。
証明プロセス
問題の変換によって、以下のように証明プロセスを構築できる。
証明者はにおけるとの値をマークルツリーにして、マークルルートを検証者にコミットする
検証者は16個の値を選び証明者に送る
証明者はにおけるとのマークルパスを検証者に送る
検証者はマークルパスからマークルルートを構成できること、がにおいて成り立つことを検証する
検証が通れば、証明者はを知っていることを証明できる
図で表すと以下の様になる。
更に、証明者はマークルルートをエントロピー源としてを生成することで、このプロセスを非対話式にできる。これは、マークルルートを任意の値にすることが困難であるために安全に機能する。
脆弱性1
仮に攻撃者がなると次数が同じ多項式を偽造した場合を考える。
まず、数学的事実としてN次多項式同士の交点はたかだかN点しかない。とは次多項式なので、交点はたかだか点しかない。つまり、偶然が成り立つ確率は最大でもとなる。証明プロセスでは16個の値を使用しているので,偶然検証を通過する確率はとなる。
今回はの次数がと同じ場合を考えたため安全そうに見える。しかし、仮にの次数が非常に大きい場合を考えると交点も非常に多くなるため、偶然が成り立つ確率はよりも遥かに大きくなってしまう。
つまり、この攻撃を防ぐためには証明者が提供するとの次数に上限を設ける必要がある。
脆弱性2
次に、攻撃者が以下の様にとを偽造した場合を考える。
の代わりに適当な値を使う
の代わりにを使う
この場合、は常に成り立つため検証を通過する。
つまり、この攻撃を防ぐためには証明者が提供する点の集合が、ある多項式上に存在することを検証する必要がある。
解決策
これらの脆弱性に対応するため、low-degree testingの一種であるFRIを導入する。これによって、証明者から提供された点の集合が確かにある次数未満の多項式上にあることを検証することで、上記の攻撃手法を防ぐことができる。
STARKs, Part II: Thank Goodness It's FRI-day
証明者が提供した点の集合について、それら全てが次数未満の同じ多項式上にあると主張することを考える。
仮に割の点が多項式上に無い場合、この主張は回の(検証者側の)クエリでの確率で検証を通過する。(ラグランジュ補間を使えば個の点から次多項式を作れるため)
このままでも良いが、が大きい場合は大変なので、以下のテクニックを使って証明者・検証者の計算量を削減していく。
二変数関数
個の点が次数未満の多項式上にあるとする。
まず、を満たすような二変数関数を見つける。見つけ方は簡単で、の次の項を以下の様に変換すればよい。
例えばという項は以下のように変換される。
この変換を用いると、次に記すように回のクエリ以下で検証を行う事ができる。
証明プロセス
二変数関数を用いて以下のように証明プロセスを構築できる。
証明者はを計算して以下の正方形を作成し、×個の値をツリーにしてマークルルートをコミットする(正方形の対角線はの値を意味する)
検証者は行と列を数十個指定して、各行/列に対して個の点を要求する (このうち一つは対角線上の点)
証明者は指定された点におけるの値とマークルパスを提出する
検証者はマークルパスが正しいこと、各行/列の点が次数<1000の多項式上にあることを検証する
検証が通れば、証明者は提供した点の集合がある次数未満の多項式上にあることを証明できる
は次数未満の多項式であったが、行と列を指定( or を固定)することでを次数1000未満の多項式にすることができた。
例として30行, 30列, 1010点を指定すれば、60600点にアクセスすることになり、元の未満のクエリよりも大幅に少なくなっていることが分かる。
更なる効率化1
フェルマーの小定理より、有限体においてがの倍数ならば、関数は通りの値のみ出力することが知られている。
この数学的事実を基に更なる効率化を行う。まず、有限体の位数としてより大きく、素数であり、がの倍数であるを選ぶ。このとき、関数は個の出力しか持たない。
これを利用すると、正方形の列方向の値の個数は、からに減少する。つまり、計算の複雑さはからに減少する。
この図を見ると、列方向が有限体で記述されているために、対角線がループしていることに気づく。つまり、一つの行に対角線上の点が1000点含まれているということである。この事実を利用すると、証明者は対角線上の値のみコミットすれば良く、検証者はある一組の行と列を指定すれば十分に証明を満足する結果が得られる。
更なる効率化2
先ほどの考え方を導入すると、証明プロセスは以下の様になる。
証明者は対角線の値のみ計算してコミットする
検証者は一組の列と行を指定する
証明者は列の値と、行の対角線上の1000点を提出する
検証者は列の値から次数1000未満の多項式を構成できること、対角線上の1000点から次数999の多項式を構成できること、列と行の交点が多項式上にあることを検証する
検証が通れば、証明者は提供した点の集合がある次数未満の多項式上にあることを証明できる
よって、計算の複雑さはからに減少する。
更なる効率化3
ではなく、を採用すると、行方向は次数2の多項式、列方向は次数の多項式となる。
列方向の多項式に同様の操作を再帰的に繰り返すと、計算の複雑さは以下の様になり、更なる効率化を達成できる。
Last updated