きの仮想通貨コントラクトをデプロイしてみる(前編)どうも、ぺろりんです。Books)」でやっていきます。今回は、教科書的には「キャッシュバック機能付き仮想通貨コントラクト」の続きです。書いているうちに長くなってしまったので、前編と後編に分けることにしましたw本当ならもう少し早くこれをやりたかったんですが、今回の内容は個人的につまずく箇所がいくつかあったので、「コントラクトの継承と連携(他のコントラクトのメソッド実行)」という記事をはさんでみました。今回やりたいのは、暗号資産(仮想通貨)が1つあって、これに「紐づくユーザーが各々会員情報を持つ」状況をコントラクトで表現することです。以下では教科書にあるサンプルコードをデプロイして、動きを追いつつコードについて考えたことなどをコメントしていきます。VMを使い、すべてweb上で動かします。アドレスのまとめ先に、今回使うアドレスをまとめておきます。今回は、以下4つのアドレスが登場します。先ほど大まかにご紹介した「やりたい」ことを、コードでどう表現されているかを軽く触れておきます。コントラクトのコードとしては、だいたい以下のような構造になっています。き仮想通貨コントラクト「OreOreCoin」の3つが1つの.solファイルに書かれている。(2)(コードの見通しをよくする目的で)「Members」と「OreOreCoin」が「Owned」のサブコントラクトになっている。(3)「OreOreCoin」に定義された関数の中で、「Members」で定義された関数を呼び出しているこの(3)が、個人的にはポイントだと思っています。(後から出てきますが)動作させる上では、「Members」に定義された状態変数「coin」に「OreOreCoin」のデプロイアドレスを入れるので、(3)と合わせると「Members」と「OreOreCoin」が入れ子みたいな構造で動きます。́Д`)各コントラクトは以下のような内容です。・Owned...オーナーアドレス「owner」の定義と、オーナーアドレスの変更をする。・Members...状態変数として会員情報を定義し、会員情報と取引履歴を更新する関数を持っている。・OreOreCoin...暗号資産(仮想通貨)OreOreCoinを定義し、送金、ブラックリスト、キャッシュバック機能を、Membersの情報を使いながら実装する。Books)」をご参照ください。コントラクトのデプロイいつも通り、サンプルコードをコピペして、コンパイラのバージョンをコードに合わせてコンパイルします。VM」にしつつ、教科書通りユーザーA(ここでのアドレス:0xca35b7d915458ef540ade6068dfe2f44e8fa733c)で「Members」をデプロイします。今回は前の記事のように「new」していないので、いきなり「Members」をデプロイして「Owned」がデプロイされるのか気になっていましたが、「owner」にユーザーAのアドレスが入っているところを見ると、どうやらサブコントラクトをデプロイすると親コントラクトもデプロイされるみたいですね。......というかむしろ、「Owned」がデプロイされているというよりも、「Owned」に(「クラス」的に)定義された部分はソースをコンパイルした時点で「Members」内でもデプロイできる状態になるので、“「Members」内に(継承された部分として)定義された「Owned」部分”がデプロイされて、“「Members」内に(継承された部分として)定義された”「owner」に値が入ったと考えるべきなのかな。Members.owner」と出ていたりするので、ここでは「Members」の「owner」(=Members.owner)ってことみたいですね。教科書通りにサクッと会員ステイタスをpushしていきます。ここで使う「pushStatus」は「onlyOwner」修飾子がかかっているので、「Members」のオーナーしか実行できません。「各メンバーが自分でステータスを変更」ということはできません。一応、教科書に沿って「Members」のオーナーをユーザーB(0x14723a09acff6d2a60dcdf7aa4aff308fddc160c)にしておきます。この「transferOwnership」も「Members」のオーナーしか実行できません。(という意図なんだと思います。)せっかくなので、まだオーナーになっていないユーザーBのアドレスで、ユーザーBが自分をオーナーにするように「transferOwnership」を実行してみましょう。やってみると......やはりユーザーBはオーナーではないので怒られます。気を取り直してユーザーAで実行すると、無事に「owner」がユーザーBのアドレスになります。会員管理機能付き仮想通貨コントラクト「OreOreCoin」のデプロイ例のごとく教科書に沿って、ユーザーAで「OreOreCoin」をデプロイします。「OreOreCoin」のオーナーアドレスには、ちゃんとユーザーAのアドレスが入っています。「OreOreCoin」のデプロイアドレス(0xdc04977a2078c8ffdf086d618d1f961b6c546222)も、後で使うのでコピっておきます。「Members」と「OreOreCoin」の紐づけここがなかなか理解できなかったのですが、「Members」と「OreOreCoin」を、各々のデプロイアドレスを使って紐づけていきます。やることは以下の2つです。(1)ユーザーBで、「Members」のデプロイアドレスを引数にして(「OreOreCoin」内で定義された)「setMembers」を実行する。(2)「OreOreCoin」のデプロイアドレスを引数にして(「Members」内で定義された)「setCoin」を実行する。(こちらは「Members」のオーナーアドレスという意味で、ユーザーBで実行する必要があります)まず(1)をやってみます。次に、(2)を実行します。上記(1)、(2)で、以下の図のようなことをしています。(逆に混乱しちゃったら無視してくださいw)私が理解するにあたって、以下がポイントでした。(A)「setMembers」は「OreOreCoin」、「setCoin」は「Members」内に定義されている。(名前が入れ子になっていてややこしい)(B)「setMembers」の定義には「msg.sender」が入っているため、実行ユーザーを気にする必要がある。(後述しますが、「onlyOwner」修飾子がついている「setCoin」も実行ユーザーを気にする必要があります)(C)「coin」はただのaddress型だけど、「members」はmapping型なので“配列”になっている。(「mapping」は「連想“配列”」であることを忘れていて、当初スカラー量のイメージで読んでいたせいで理解がなかなか進みませんでしたw)「会員ごとに会員情報を持つ」ことを、(B)→会員アドレスと会員情報(=Members)の紐づけることで、会員が会員情報を持つこと(C)→会員アドレスをインデックスとする配列(members)によって、会員ごとに情報を持つことという風に実装しています。ここまでで、ユーザーBの「Members」コントラクトが準備できました。前編はこのへんで、後編へ続きます。1))どうも、ぺろりんです。1))、読んでみたらすごく面白かったwというかこのブログめっちゃ良いぞ!!......というわけで、自分の勉強がてら翻訳してみました。皆さんの勉強のご参考になれば幸いです。(その1)概要この連載では、確率論的なプロトコルの1つで、Goldwasser、Micali、Rackoffにより1985年に初めて記述され、分散台帳技術(DLT)の盛り上がりとともに人気が出てきたゼロ知識証明(ZKPs)について見ていく。この画期的な仕事の背後にあるいつくかの理論の紹介と、その複雑な機構の種々の要素をどのように実行するのか示すことから始める。Pinocchioプロトコルに従いPythonで実行して、最終的には例題に関するエンドツーエンド[訳注1]のゼロ知識証明になる。主な目標はこのトピックのやさしい入門を提供することで、ZKPsに関する簡潔な数学をかみ砕いて、その背後にあるいくつかの直観的なことを議論する。これに沿って、この技術によって可能になる、いくつかのエキサイティングな応用についても触れる。そもそも、ZKPとは何のことで、なぜこれを気にしないといけないの?ZKPは、「証明者(彼女のことはPeggyと呼ぶことにしよう)がある秘密を知っている」ことを秘密の内容を明かさず、承認者(彼のことはVictorと呼ぶことにしよう)にどんな合理的な疑問も残さない証明を与える。Peggyは、具体的な素因子を明かすことなく非常に大きい合成数の素因数分解を知っていることだったり、解答自体は明かさずに与えられた数独パズルの答えを知っていることをVictorに証明したいのかもしれない。一般的には、ZKPsは検証可能な計算の構成要素として使える:これは弱いクライアントからより計算力の高いワーカーに計算を押し付ける方法で、元のプログラムを実行するのに比べてかなり小さい労力の計算でワーカーが実行した計算の正しさを、クライアントが暗号的学的に証明することができるようなもの。これは、クラウドだけでなく、オンラインのプライバシー、DLTのスケーラビリティや携帯アプリ、その他諸々の応用に影響する非常に強力なパラダイムになっている。ZKPsについて別の有望な応用は、機械学習の分野にある。この文脈でこの技術は、第三者がモデルのトレーニングや予測の過程で特定のデータが使われたことを証明できるだけでなく、すべてを開示する必要なく特定のデータを持っていることを証明するのに使える。primitives)[訳注2]の先駆的プレジェクト。実のところ、ZKPって何?非常に簡単に言うと、コンピューター上で表現されるとZKPは、Peggyによって注意深く計算され、Victorが計算が正しいことの証明を検証するために実行するたくさんあるブール型のチェックと一緒にして数を並べたものでしかない。したがって、ゼロ知識証明のプロトコルはこれらの数から導かれ、検証の確認で定義される。よる初めの論文(1,2,3,4,5)が出版されてから色んなプロトコルも提案されている。これらのプロトコルの主な違いの一つは対話性にある。対話的なゼロ知識プロトコルでは検証者が「証明者がある秘密を知っている」ということを信じられるまで、証明者と検証者がたくさんのメッセージをたがいに交換する。各やり取りのラウンドはVictorによって出された「Peggyが正しい解答を提出しないといけない」問題で、その解答はVictorに検証され、プロトコルによって特徴づけられるブール型のチェックを通過したときにだけ受理される。Peggyがその秘密を知らずにNラウンドすべてチェックに通貨してしまう確率は、Nについて指数関数的に減少する。したがって、Victorは内容については何も知ることがないにもかかわらず、「Peggyがその秘密を知っている」ことをVictorが確信できるまで好きなだけ長く、行ったり来たりするやり取りを続けられる。逆に、非対話型のゼロ知識プロトコルでは、証明者と検証者の間でやり取りが繰り替えされることがない。代わりにただ1つの"ラウンド"があり、これは非同期的に実行される。公開されているデータ(続くセクションや投稿で議論される予定の内容)を使い、Peggyが証明を作り、Victorが利用できる場所に公開する(たとえば分散台帳上に置く)。これにより、Victorは"ラウンド"完了するため、いつでもその証明を検証できる。対話的な場合はたくさんの証明を作るのに対しPeggyはただ1つの証明を作るとしても、無視できる確率を除き、「彼女が、自分で主張する秘密を確かに知っている」ことを検証者は依然として確信できる。結果的に、非対話型アプローチの利点の1つとして、「検証者に依らない」ことがある。Peggyの証明は、手元にあるその問題の実例(たとえば数独パズル)について普遍的で、Victorだけでなくどんな検証者でも、Peggyの「私は解答を持っている」という主張を後から検証できる。ゼロ知識プロトコルたちの別の違いは簡潔性にあって、Peggyによって生成される証明のサイズを扱う。簡潔性は、ストレージ容量と検証時間という2つの理由で、分散台帳上に発行されたZKPについて重要な役割を担う。ストレージは非常に高価で、たとえば現時点でビットコイン、イーサリアム、NEO、EOSで各台帳に1KBを保存するときの費用はそれぞれ、$3.83、$2.86、$19.38、$3.00となっていて、ピーク時の費用はもっと高い!変動価格と高価なストレージの効果は、1KBあたり$0.001であるファクトムなどの安価で低価格の分散台帳を使うことで相殺できる。かかわらず、証明のサイズはできるだけ小さく保つことが依然として望ましい。加えて証明は素早く検証できることが必要で、そうでないとサードパーティにオフロードする効果が薄れる。したがって、チェーンなしのアプリケーションにとって、検証時間が一定であるだけでなく、生成された証明ができるだけ短くて、理想的には問題の内容によらないことが非常に重要となる。自然な疑問として、「対話型の証明が好まれる場合があるのか?」ということがある。多くの非対話型プロトコルは、一般に「信頼されたセットアップ」といううるさい問題に悩まされていることがわかるが、これは各々を対話型にした代替プロトコルには存在しない。信頼されたセットアップは、証明を計算するときPeggyに利用される公開データの一部を生成するプロセスにある。このセットアップの詳細は後で議論予定だが、簡単に言うと、このセットアップは、乱数源から発生するある数(一般に「有害廃棄物」と呼ばれる)を公開する集団や、集団が集まった大きな集団による。この乱数源にアクセスする誰もが、プロトコルに従って検証者が受け入れるような偽の証明を生成できる。このような理由で、公開された数を生成する集団によって「有害廃棄物」が破壊されることが重要で、これはこのような集団が信頼される必要があることを意味する。これは実質的に、いつくかの非対話型ゼロ知識プロトコルの適用可能性を扱いにくいものにする。多くの場合、非対話性や簡潔性では大して得をするわけではない。非対話性は、たくさんの独立な検証者が、与えられた証明を各々個別に証明者へ問い合わせを行わずに検証したいときにのみ有用となる。簡潔性は、証明を保存するために使われる中間物が非常に高価か、非常に短い検証時間を求めているときのどちらかまたはこの両方であるときにのみ必要となる。分散台帳は特段の例外として一般にストレージは安価で、パブリックブロックチェーン上のブロック間時間に強いられるような厳しい制約がなければ検証時間もまた柔軟であり得る。これは、2つの対象がHTTPSのように安全なチャネルを使ってやり取りするようなB2Bアプリケーションでは、対話型の証明でやっていけることを意味する。検証者は信頼されたセットアップを実行する責任があるとして、ユースケースに応じて企業がPeggyかVictorの皮をかぶることができる。このやり取りは自然に1対1なので、検証者は偽の証明には興味がなく、オンチェーンに証明を保存する必要もなく、Victorは検証を実行する時間をより多く割く余裕があり、このようなアプリケーションは対話型の状況ではたらく。このちょっとした遠回りに続いて、この連載で興味のある主題である、非対話型で簡潔な証明に戻る。ここではゼロ知識(zero-knowledge)で、簡潔(Succinct)かつ非対話型(Non-interactive)の計算による知識証明、またの名を「zk-SNARKs」というものに興味がある。特筆すべきアーリーアダプターの中でも匿名暗号通貨のZcashと、スマートコントラクトのプラットフォームであるEthereumで使われており、zk-SNARKsはゼロ知識プロトコルで最も広く使われている。QAP:計算から多項式へzk-SNARKプロトコルをより厳密に説明する前に、いくつかの背景に言及しておかないといけない。ゼロ知識プロトコル一般に言える複雑なことの1つとして、これらを適用可能にするために、元の問題を完全に変形してやらないといけない、ということがある。解を知っている」ことを、この解が何かを明かすことなしに証明したい、という状況を考える。この場合解は自明で、誰でもこの解答を導けるので現実的にはこの問題にゼロ知識証明は不要だが。それもかかわらず、2次多項式に代わってこれを1万次の多項式に簡単に拡張できることを念頭に置きつつ、話を簡単にするために、この連載ではこの例を見る。Programs)にあり、さらなる読みものとしてこれを強くおすすめする。ここでは、この「変形」の短いまとめを提供する。コードでこの問題を表すことから始める。Pythonでは、計算を読み替える、次の簡単な関数を定義できる。y=x**2-4Peggyとしては「自分だけが知っているある秘密の値xにおいて上の関数を評価すると、yが0になる」ことが目標。明らかに、少なくとも2つの問題がある。・xの値は知ることなく、関数を実行する最後にyの値の"ピーク"をVictorが得られる方法を見つける必要がある。・Peggyはプログラムの実行者なので、コードの今の定式化では、VictorはPeggyが確かに実行したどんなコードも制御できない。Peggyは条件を満たすy=0というだけのコードを走らせるズルをすることもできる。これらの問題のどちらも、解決がとても難しいように見える。この答えは上述した問題のかなり非自明な再定式化を必要とし、すなわちこれのQAPへの変換が必要となる。system)への変換、最後にQAPの定式化、という3つのステップを踏む。コード平坦化のゴールは、任意の複雑な主張や表現を含むような元のコードを、次の2つの形からなる一続きの主張に変換することとなる。(ここで、op∈(+,-,*,/)であり、yとzは変数でも、ある数でも、部分式でも良い)これらの主張を算術回路のゲートとして考えられる。ここで出している例のプログラムの回路は、次のように見られる。対応する「平坦化されたコード」は次のようなものになる。4次のステップでは、これをR1CSに変形する。ここで、〈・,・〉は2つのベクトルのドット積(内積)を表す。探して満たす必要のあるような拘束条件を定義していると解釈できる。例に挙げているコードの平坦化したものをR1CSに変換する、自然な方法がある。プログラムの主張を満たすようなベクトル(すなわち、プログラム内で使われるすべての変数)を定義する。各変数を割り当てたものになる。今のプログラムの変数ベクトルは、次のようなものになる。y)T1つ目の成分として1を含むのは、後で簡単に見るように、これによって拘束条件を満たすようにするため。このベクトルを定義して、平坦化したコードの各行を順次処理して適切なai、bi、ciを定義することで、今の行に含まれる計算の読み替えを続ける。この関数の中身で最初の行を読み替えるには、以下のように設定する。0)T2行目の読み替えには以下を使う。1)Tこの2つの行について、読み替えを展開してチェックしてみる。2行目で-4という定数を表すために、aiの定義のところでsの第1成分で1をどう使うかも見る。ci)のトリプレットに"移送"された。任意)を満たすようなsの成分を見つけることと等価になっている。QAPへの変形を完了するのに、ベクトルから多項式へ転換する必要がある。Ai(x)、Bi(x)、Ci(x)を定義することから始める。ここで、Nは制限ベクトルの成分の数(今の場合は4)となっている。(Bi(n)、Ci(n)も同様)と要請し、これらの点に基づいたLagrange補完をすることでこれらの多項式を構成する。今の例では次のように要請する(Bi、Ciも同様)。0Lagrange補完をすると、次の多項式に到達する。1これらの定義によって、今や1つの方程式として上記をR1CSで表現できる。Z(x)を満たすようなものであると要求する。ここ?よろしい!ここで、次のようなことが疑問じゃないだろうか。・なんでこんなことしたの?・Z(x)ってなんやねん・H(x)は何者で、誰が思いつくの?これらの質問に答えるため、まず次のようなことを見る。a2として、B(x)とC(x)も同様とする。A(x)、B(x)、C(x)の定義も用いると、これは元のR1CS系が以下と等価であることを意味する。2)これはH(x)とZ(x)が何かを明らかにしてくれる。して計算することにより、背後にあるR1CSを満たすsの成分を知っていることを示すので、H(x)を計算するのは証明者だろう。Z)という4-タプル[訳注4]、sをこのQAPの"解"と考えることができる。大事な質問にまだ答えていない。こんなことをする必要があるのだろうか?Pythonのプログラムとして今の問題を表現していたことを思い出すと、次のような1組の大きな問題に突き当たる。・Peggyが正しいプログラムを動かしていることを検証する方法が無い・他のどのんな情報も明かさずに、プログラム実行の最後におけるyの値をどうやってVictorに観測させるかが明確でないR1CSとして表現された計算だと、Victor妥当なsの割り当てを見るとすると、Peggyが対応するR1CSのプログラムを実行したことを確信できる!これは主な問題の1つをすでに解決している。QAPを得るためにR1CSをさらに変形する理由は、多項式で説明する方がR1CSで説明するよりも有益だから。次のセクションではこの新しく提案された「問題の再定式化」を、zk-SNARKsを構成する中心となる1つの技術を説明するのに使うが、これは多項式の構造を利用する。多項式を処理するうまいやり方の1つに、知らない点で多項式を評価するものがある。polynomials)としても知られる。まってwつまり......どういうことだってばよ?!そう、お分かりの通りこれは不可能に違いない。xnについて、この多項式を評価したいとすれば、xを知らなければいけない。f(x)≠f(y)このような関数がどのように目隠し評価する助けになるのか見てみよう。簡単に可視化するために、Peggyがこの問題においてその点で多項式を評価したとVictorが検証できるような方法で、VictorがPeggyに、どちらもが知っているPの目隠し評価を問い合わせるとする。fは存在して、PeggyもVictorも知っている知っているとする。