🔗 スマートコントラクトの設計とインターフェース定義
このレッスンでは、ゼロ知識証明を使ってNFTをミントするスマートコントラクトZKNFT.solの全体像を設計し、証明を検証するための「窓口」となるインタフェースを定義します。
🏛️ スマートコントラクトのアーキテクチャ
このプロジェクトのバックエンドは、2つの主要なスマートコントラクトが連携して動作します。役割分担が重要です。
-
PasswordHashVerifier.sol(検証者コントラクト) 🕵️♂️:-
これは、前のセクションで
circomとsnarkjsを使って自動生成されたコントラクトです。
私たちはこの中身を直接編集しません。 -
役割はただ一つ、「提出されたゼロ知識証明が正しいかどうか」を厳格に検証することです。
verifyProofという関数を持っており、これ に証明データを渡すと、有効であればtrueを、無効であればfalseを返します。まさに門番のような存在です。
-
-
ZKNFT.sol(NFTコントラクト) 🖼️:-
こちらが私たちがメインで開発するコントラクトです。
-
OpenZeppelinの
ERC721標準を継承しており、NFTとしての基本的な機能(所有権の管理、転送など)を備えています。 -
NFTをミントするための特別な
safeMint関数を実装します。この関数の内部で、門番である
PasswordHashVerifier.solに「この証明は本物ですか?」と問い合わせます。証明が有効な場合にのみ、NFTのミントが実行される仕組みです。
-
このように役割を分離することで、検証ロジックとアプリケーションロジックが明確に分かれ、コードが整理されて読みやすく、メンテナンスしやすい状態になります。
✍️ 検証コントラクトのインタフェースを定義する
ZKNFT.solがPasswordHashVerifier.solのverifyProof関数を呼び出すためには、その関数の仕様(どのような引数を受け取り、何を返すか)を定義した 「インタフェース」 が必要です。インタフェースは、異なるコントラクト同士が安全に通信するための「共通言語」や「取り決め」のようなものです。
まず、pkgs/backend/contracts/interfaceディレクトリを作成しましょう。
mkdir -p pkgs/backend/contracts/interface
次に、pkgs/backend/contracts/interface/IPasswordHashVerifier.solというファイルを作成し、以下のコードを記述します。
// pkgs/backend/contracts/interface/IPasswordHashVerifier.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
/**
* @title IPasswordHashVerifier
* @dev `PasswordHashVerifier.sol`と通信するためのインターフェース。
* snarkjsによって自動生成された検証コントラクトの`verifyProof`関数を定義します。
*/
interface IPasswordHashVerifier {
/**
* @dev Groth16 ZK-SNARKの証明を検証します。
* @param a 証明のコンポーネント
* @param b 証明のコンポーネント
* @param c 証明のコンポーネント
* @param input 公開入力(このプロジェクトではパスワードのハッシュ値)
* @return r 検証が成功した場合はtrue、それ以外はfalse
*/
function verifyProof(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[1] memory input
) external view returns (bool r);
}
🔍 コード解説
-
interface IPasswordHashVerifier:
これがインタフェースの定義です。ZKNFT.solは、この「取り決め」に従って検証コントラクトと対話します。 -
function verifyProof(...):
snarkjsが生成したPasswordHashVerifier.solに含まれるverifyProof関数のシグネチャ(関数名、引数、戻り値の型)を正確に定義しています。a,b,c:
これらはGroth16証明を構成する主要なデータです。クライアント(フロントエンド)から証明として提供されます。input:
これは証明の**公開入力(public input)**です。
私たちの回路では、パスワードのハッシュ値がこのinputに対応します。returns (bool r):
関数がbool型(trueまたはfalse)の値を返すことを示します。
このインタフェースを定義することで、ZKNFT.solはPasswordHashVerifier.solの複雑な内部実装を一切知らなくても、verifyProof関数を安全に呼び出すことができるようになります。
準備は整いました! 次のレッスンでは、このインタフェースを使って、ZKNFT.solコントラクト本体をステップバイステップで実装していきます。
🙋♂️ 質問する
ここまでの作業で何かわからないことがある場合は、Discordの#zkで質問をしてください。
ヘルプをするときのフローが円滑になるので、エラーレポートには下記の3点を記載してください ✨
- 質問が関連しているセクション番号とレッスン番号
- 何をしようとしていたか
- エラー文をコピー&ペースト
- エラー画面のスクリーンショット