原文
ERC-8287: Privacy-Native Fungible Tokens — Cyimon (2026-06-04)
著者: Cyimon (@Cyimon) · ステータス: ドラフト · タイプ: 標準トラック · カテゴリ: ERC · 作成日: 2026-06-03
概要: Zcash Orchardプロトコルを搭載した、EVM上のプライバシーネイティブなファンジブルトークンインターフェース。
関連議論: ethresear.ch #25089 · 実装: PERC20Labs/PERC20 ·
この行以下のすべてをMagiciansトピック本文に貼り付けてください。投稿前にプレビューを使用してください。推奨カテゴリ: ERCs。タグ:
privacy,zk-snarks,standards,erc-20。
簡易要約
EVM上のプライバシーネイティブなファンジブルトークン(ZK-UTXOノート、Orchardスタイル)で、公開されたtotalSupplyとプライベートな残高/転送を持ち、Zcash Orchardプロトコルによって強化されています。
概要
EVM上でZK-UTXOノートを使用する、プライバシーネイティブなファンジブルトークンインターフェースです。公開されたtotalSupplyを持ち、残高と転送はプライベートです。実装は、プライベートな残高と転送量をデフォルトで提供しつつ、公開検証可能なtotalSupplyを維持した転送、発行、焼却を提供します。トークンは、発行時から暗号化されたUTXOノート(Groth16証明、Orchardスタイルのモデル)として存在します。各pERC20アセットは、アセットコントラクトによって維持されるコンプライアンス凍結ルートにバインドされなければならず、ブラックリストに載ったノートが使用できないようにします。
この提案は、ERC-20とバイナリ互換ではありません。公開されたbalanceOfやapprove / allowanceはありません。代わりに、同等のプライバシーインターフェースIPERC20を定義します。
この提案は、ETHおよび互換性のあるERC-20アセットのプロトコルレベルのプライベート転送レイヤーを補完するものであり、pERC20はアセットレベルでプライバシーネイティブなトークンインターフェースを定義します。
動機
イーサリアムは、プロトコル層でのネイティブなプライバシーにますます注力しています。ベースレイヤーのプライバシープリミティブが成熟するにつれて、エコシステムは、公開トークンに対するERC-20と同様の役割を持つプライバシーネイティブなファンジブルトークンインターフェースを必要とするでしょう。
このドキュメントは、そのギャップを埋めるために**pERC20**を提案します。これは、OrchardスタイルのZK-UTXOモデル(Groth16証明、Zcash Orchardプロトコルから適応)に基づいて構築された、EVM上のプライバシーネイティブなファンジブルアセットの規範的なインターフェースです。対照的に、ERC-20は残高と転送を完全にオンチェーンで公開し、保有者の分布、取引相手、および金額を明らかにします。pERC20は、以下の目標を持つノートベースのUTXOモデルを採用しています。
追加の背景と初期レビュー: ethresear.ch #25089。
- デフォルトでのプライバシー: アセットは発行時からプライベートであり、公開からシールドへの変換ステップは不要です。
- UTXOレベルのプライバシー: アカウント残高はパターン分析の対象にならず、同種のノートから匿名セットが形成されます。
- 検証可能な正直さ:
totalSupplyは公開されており、見えないインフレを防ぎます。 - 組み込みのコンプライアンス: プロトコル層は、規制上の措置可能性要件を満たすために特定のノートを凍結できます。
- EVMデプロイ可能性: 標準インターフェースにより、ウォレット、インデクサー、およびサービスによる統一された統合が可能になります。
仕様
このドキュメントにおけるキーワード「MUST」、「MUST NOT」、「SHOULD」、「MAY」は、RFC 2119に記述されている通りに解釈されます。
用語
| 用語 | 意味 |
|---|---|
| note | 値(トークン量)と受信者情報を含む暗号化されたUTXO |
| commitment / cmx | ノートコミットメント(マークルツリーのリーフ、x座標) |
| nullifier / nf | ノートを使用する際に公開される1回限りの公開マーカー。二重使用を防ぎ、IDとはリンクできない |
| anchor | 使用時に参照される過去のマークルルート |
| perc1 address | pERC20を受信するためのプライバシーアドレス(Orchardキー導出)。この仕様内で定義される(別途のコンパニオンERCなし) |
| frozenRoot / rt_frozen | コンプライアンスブラックリストのSparse Merkle Tree (SMT)のルート。公開された回路入力 |
| binding signature | 値の保存を証明するシュノア署名 |
| spend-auth signature | ノートを使用する権限を証明するシュノア署名 |
| bundle | 1つ以上の行動(各行動 = オプションの消費 + 1つの出力)からなる単一の操作 |
データ構造
以下の仕様はSolidity 0.8.20(またはそれ以上)の構文を使用しています。
PrivacyCall
IPERC20メソッドのプロダクト層コールペイロード。
struct PrivacyCall {
bytes actions; // = abi.encode(BundleAction[])
uint256[3] bindingSig; // [Rx, Ry, s] Baby JubJub Schnorr binding signature
}BundleAction
IEndpointCoreの実装層アクション。
struct BundleAction {
bytes32 cmx; // output note commitment
bytes encCiphertext; // recipient ciphertext; length MUST match the note encryption format (see below)
bytes outCiphertext; // sender self-recovery ciphertext; length MUST match the OVK encryption format (see below)
bytes32 epk; // ephemeral public key
bytes32 nfOld; // nullifier of the consumed (or circuit-constrained dummy) input note
bytes32 anchor; // historical root used by the consumed input note
bytes proof; // Groth16 proof = abi.encode(pA, pB, pC)
uint256[8] pubFields; // public inputs; [7] MUST == cmxFrozenRoot
uint256[3] spendAuthSig; // spend authorization signature for the consumed input note
}ノート暗号文フォーマット: この標準は、特定のノートプレーンテキストレイアウトをバイトレベルの不変条件に埋め込みませんが、実装は1つを固定し、それを文書化MUSTします。参照実装は、Zcashプロトコル仕様 §7.5 Action Description Encoding and Consensus (zips.z.cash protocol PDF, action encoding and consensus)で定義されているOrchardスタイルのフィールドサイズを使用します。
encCiphertext= 580バイト:epkと受信者の受信ビューイングキー (IVK)から導出されたキーで暗号化されたノートプレーンテキストのChaCha20-Poly1305暗号文(564バイトのプレーンテキスト + 16バイトのPoly1305タグ。プレーンテキストフィールドには、ダイバーシファイア/送信キーエンコーディング、value、rseed、および512バイトのメモが含まれます)。outCiphertext= 80バイト: 送信キーとエフェメラル秘密キーから形成されたバイト文字列のChaCha20-Poly1305暗号文で、送信者の送信ビューイングキー (OVK)で暗号化され、送信されたノートの回復に使用されます(64バイトのプレーンテキスト + 16バイトのPoly1305タグ)。
ノート暗号化レイアウト(異なる暗号、異なるプレーンテキストスキーマ、異なるメモサイズ)を変更する実装は、黙って長さを変更するのではなく、このERCの別のバリアントを公開MUSTします。
pubFieldsの順序は [anchor, cv_net_x, cv_net_y, nf_old, rk_x, rk_y, cmx, rt_frozen] MUSTです。
このレイアウトは、Zcashプロトコル仕様 §4.18.4 Action Statement (Orchard) (zips.z.cash protocol PDF, action statement)におけるOrchardアクションの主要入力(anchor、ネット値コミットメントcv_net、nf_old、ランダム化キーrk、出力コミットメントcmx)から導出されています。pERC20は、コンプライアンスと統一された検証パスのために、意図的に2つの変更を加えています。
rt_frozenがenable_spend/enable_outputを置き換える: スロット[7]は、各アクションをアセットのコンプライアンスブラックリストSMTルート(IPERC20.cmxFrozenRoot())にバインドします。回路は、そのルートの下で消費されたノートコミットメントが非メンバーであることを証明します。- 発行 / 転送 / 焼却のための単一のアクション形状: ダミー入力の発行と実際の消費は同じ公開フィールドレイアウトを共有します。有効化フラグは個別の公開入力として公開されません(回路内で処理されます)。
オンチェーン実装は、これらの8つのフィールドをActionPubHash(Poseidonスポンジ)を介して単一のGroth16公開シグナルpub_hashに圧縮MUSTし、この圧縮関数は回路のPubHashAction()と一致MUSTします。
pubFieldsの各要素は、正規のフィールド要素(実装の検証者が使用するSNARK曲線の**スカラー体モジュラス** [[glossary/Fr|Fr]]よりも厳密に小さい)でなければなりませんMUST。そうでなければ、呼び出しはリバートMUSTします(PubFieldOutOfRange)。この制約がないと、ActionPubHashはハッシュ化前にフィールドを法として入力を削減しますが、SNARK検証者は最終的なpub_hashのみをチェックします。攻撃者はnf + Frを提出して同じpub_hashと証明を生成できますが、異なるisSpentキーにマッピングされ、同じノートの二重使用が可能になります。
IPERC20インターフェース
メソッド
注記:
- 実装は成功時に
trueを返MUSTし、失敗時にリバートMUSTします。boolの戻り値はERC-20呼び出し規約との互換性のために保持されています。
name
トークンの名前を返します — 例: "MyPrivateToken"。
function name() external view returns (string memory)symbol
トークンのシンボルを返します。例: "pHIX"。
function symbol() external view returns (string memory)decimals
トークンが使用する小数点以下の桁数を返します — 例: 8は、トークン量を100000000で割ってユーザー表現を得ることを意味します。
function decimals() external view returns (uint8)totalSupply
トークンの総供給量(累積発行から累積焼却を引いたもの)を返します。この値は公開されており、オンチェーンで検証可能でなければなりませんMUST。
function totalSupply() external view returns (uint256)issuer
この標準の下で発行を許可されたアドレスを返します。
function issuer() external view returns (address)cmxFrozenRoot
現在のコンプライアンス凍結ルート(IPERC20インターフェースメソッド)を返します。
function cmxFrozenRoot() external view returns (uint256)setFrozenRoot
オフチェーンのブラックリストSMTを再構築した後、コンプライアンス凍結ルートを更新します。adminに制限されなければなりませんMUST。
function setFrozenRoot(uint256 newRoot) externaltransfer
値の保存を伴う、一連のノートを秘密裏に受信者に転送します(ノート→ノート)。
実装は、valueBalance == 0で基盤となるバンドルロジックを実行MUSTします(_executeBundleなどの内部実行パスを介して)。
実装は成功時にtrueを返MUSTします。失敗はリバートによって表現されなければなりませんMUST。
実装はERC-20のTransfer(from, to, value)イベントを発行してはなりませんMUST NOT。ノートごとの可視性はNoteAdded / NoteConfirmedによって提供されます(IEndpointCoreを参照)。
送信者、受信者のID、および転送量はプライベートのままMUSTです。
値変更操作は、制御された発行 / 焼却 / 転送を通じてのみ公開されなければなりませんMUST。コア実行パスは公開呼び出し可能であってはなりませんMUST NOT。これにより、呼び出し元がvalueBalanceの方向を選択して供給会計をバイパスすることを防ぎます(供給不変条件を参照)。
function transfer(PrivacyCall calldata call) external returns (bool success)mint
額面amountの新しいノートを作成します。totalSupplyはamountだけ増加します。
実装は、バインディングスカラーamount mod ℓが宣言された量と等しくなるように、amount < ℓ(SUBGROUP_ORDER)を検証MUSTします(AmountTooLarge)。
実装は、valueBalanceの下位255ビットがamountと等しいことを検証MUSTします(金額バインディング)。
実装は、発行アクションを転送および焼却と同じアンカー / nullifier / スペンドアテステーション検証パスを通じて実行MUSTします(オンチェーンでの出力のみのブランチなし。nfOld == 0センチネルなし)。回路は、発行アクションの消費された入力ノートがv = 0を保持するように制約MUSTし、それによってアクションが純流入セマンティクスを示すようにします。これは回路レベルの不変条件であり、オンチェーンで直接チェック可能ではありません。
承認: 発行は発行者(onlyIssuer)に制限されなければなりませんMUST。
実装は、後のバージョンで発行承認を緩和MAYできます(ブロックウィンドウ、キャップ、許可リスト、PoW、ステーキング)が、totalSupplyは公開で累積され続けなければなりませんMUST。
受信者のIDはプライベートでなければなりませんMUST。amountは公開です。
function mint(uint256 amount, PrivacyCall calldata call) externalburn
値を破棄するためにノートを使用します。totalSupplyはamountだけ減少します。外部アセットはリリースされません。
実装は、amount < 2^255(符号ビットが設定されていない)およびamount < ℓ(SUBGROUP_ORDER、AmountTooLarge)を検証MUSTします。
実装は、valueBalance == amount(bit255 = 0)で実行MUSTします。
実装は、totalSupply >= amountを検証MUSTします。そうでなければリバートします。
承認: どの保有者も自身のノートを焼却MAYできます(対応するスペンドアテステーションが必要です)。
焼却者のIDはプライベートでなければなりませんMUST。amountは公開です。
function burn(uint256 amount, PrivacyCall calldata call) externalイベント
Mint
新しいトークンが発行されたときにトリガーされなければなりませんMUST。
event Mint(address indexed issuer, uint256 amount)Burn
トークンが焼却されたときにトリガーされなければなりませんMUST。
event Burn(uint256 amount)FrozenRootUpdated
コンプライアンス凍結ルートが変更されたときにトリガーされなければなりませんMUST。
event FrozenRootUpdated(uint256 oldRoot, uint256 newRoot)Perc20Createdイベント
新しいpERC20アセットコントラクトがデプロイされたときに(通常はアセットコンストラクタで)一度発行されなければなりませんMUST。
ファクトリデプロイパターンは推奨されますが、必須ではありません。アセットコントラクトがPerc20Createdイベント(または同等のコンストラクタ時メタデータ)を発行する限り、スタンドアロンデプロイメントは準拠しています。ファクトリコントラクトは規範的な標準の一部ではありません。参照実装は、発見可能性と共有検証者配線のためにファクトリ(例: PERC20Factory)を提供MAYできます。
event Perc20Created(
address indexed pool,
address indexed issuer,
string name,
string symbol,
uint8 decimals
)インデクサーとウォレットは、新しいアセットを登録するためにこのイベントをリッスンSHOULDします。ファクトリが使用される場合でも、イベントはデプロイされたアセットコントラクトから発信されなければなりませんMUST(ファクトリラッパーからのみではない)。これにより、スタンドアロンデプロイメントとファクトリバックデプロイメントが同じ観測可能なメタデータを生成します。
注記: この標準は意図的にERC-20のTransferまたはApprovalイベントを定義しません。From/toは常に隠されたノートであり、転送量はプライベートです。Transferを発行することは誤解を招くでしょう。供給量の変更はMint / Burnを通じて観測可能です。ノートごとの詳細はNoteAdded / NoteConfirmedによって運ばれます。
コンプライアンス凍結ルート
コンプライアンス凍結ルートは**IPERC20**の一部です(個別のコンプライアンスモジュールではありません)。
function cmxFrozenRoot() external view returns (uint256);
function setFrozenRoot(uint256 newRoot) external; // onlyAdmin
event FrozenRootUpdated(uint256 oldRoot, uint256 newRoot);- 各アクションの
pubFields[7]は現在のcmxFrozenRoot()と等しくなければなりませんMUST。そうでなければリバートします(BadFrozenRoot)。 - 回路は、消費されたノートのコミットメントが
cmxFrozenRootをルートとするブラックリストSMTのメンバーではないことを証明MUSTします(非メンバーシップ証明)。 - 完全なブラックリストSMT構造はオフチェーンで維持されます。ルートのみがオンチェーンに保存されます。
setFrozenRootはadmin(発行者または、デプロイメントとadmin設定に応じて、専任のコンプライアンス担当者)に制限されなければならずMUST、マルチシグ / タイムロックを使用SHOULDします。各変更は監査可能性のためにFrozenRootUpdatedを発行MUSTします。- ノートを凍結するには: オフチェーンで、その
cmxをブラックリストSMTに挿入し、新しいルートを計算し、setFrozenRoot(newRoot)を呼び出します。凍結を解除するには、削除して再度setFrozenRootを呼び出します。 - 初期の
cmxFrozenRoot == 0は空のブラックリスト(デフォルトで許可)を示します。
IEndpointCore
基盤となるノートステートマシンは以下を公開MUSTします。
interface IEndpointCore {
function activeRoot() external view returns (bytes32);
function isValidAnchor(bytes32 root) external view returns (bool);
function isSpent(bytes32 nf) external view returns (bool);
function treeSize() external view returns (uint256);
event NoteAdded(
bytes32 indexed cmx,
bytes encCiphertext,
bytes outCiphertext,
bytes32 epk,
bytes32 nfOld,
bytes32 cvNetX
);
event NoteConfirmed(bytes32 indexed cmx, bytes32 newRoot, uint256 position);
event BundleExecuted(uint256 valueBalance, uint256 amount, bytes32 recipientMeta);
}実装は以下をMUSTします。
- nullifierセットと回路内の正しい
nf導出を介して二重使用を防ぎます。isSpentが設定されたら、ノートは再度使用可能であってはなりませんMUST NOT。 isValidAnchorを介してクエリ可能な履歴ルートを持つ、追加専用のマークルコミットメントツリーを維持します。- バインディング署名を介して値の保存を検証し、スペンドアテステーション署名を介してスペンドアテステーションを検証します。バインディング署名検証は、状態変更(ツリー挿入、nullifierマーク、イベント発行)の前に完了MUSTします。
- 重複する
cmx(DuplicateCommitment)とゼロコミットメントcmx == 0(ZeroCommitment)を拒否します。 - バインディング / スペンドアテステーション署名ポイント
RがSNARK曲線とペアリングされた署名曲線(参照実装はBaby JubJubを使用)上にあり、正規のフィールド座標(< Fr)を持つことを検証します。 - 各アクションの
pubFields[7] == IPERC20.cmxFrozenRoot()を検証します(コンプライアンスバインディング)。 - 空の
BundleAction[]配列を拒否し、呼び出しごとのアクション数に上限(maxActions)を設けますMUST。上限は有限で設定可能な正の整数でなければなりませんMUST。合理的な上限は、証明検証ガスを予測可能に保つために10〜50の範囲です。
実装は、すべての特権構成変更(検証者ローテーション、管理者転送、maxActions)に対してイベントを発行SHOULDします。管理者転送は、ゼロアドレス禁止の2段階フロー(transferAdmin + acceptAdmin)を使用SHOULDします。
供給不変条件
totalSupply会計を持つアセットコントラクト(例: PERC20)は、値の変更を制御された発行 / 焼却 / 転送を通じてのみ公開MUSTします。コア実行パス(例: _executeBundle)は公開呼び出し可能であってはなりませんMUST NOT。そうでなければ、誰でもtotalSupplyを増加させることなく、未計上の値を注入できてしまいます。
NoteAddedはoutCiphertext(80バイトの送信者自己回復暗号文)とcvNetX(= pubFields[1])を運ばなければなりませんMUST。これにより、送信ビューイングキー (OVK)を保持するウォレットは、calldataを解析することなくログから送信されたノートをスキャンできます。
値残高エンコーディング
valueBalance(uint256)の符号ビットエンコーディングは以下に従わなければなりませんMUST。
理論的根拠
ノートモデルとERC-20セマンティクス
- アカウント残高ではなくUTXOノート: アカウント活動パターンの漏洩を回避します。同種のノートはより強力な匿名セットを提供します。
- バイナリ互換性なしのERC-20セマンティクス: 公開残高の欠如を正直に反映しつつ、エコシステムの認知的コストを低減します。バイナリERC-20互換性は残高の公開を強制し、設計目標と矛盾します。
- 公開
totalSupply: 高価なレンジ証明なしで「見えないインフレなし」を検証可能にするための最小限の透明性トレードオフです。 - 発行はダミー入力(
v=0)を使用しつつ、焼却/転送と同じ検証パスを共有: 発行の純流入セマンティクスを維持しつつ、単一のアクション検証フローを維持します。回路のインクリメントは、単一の追加公開入力rt_frozenに収束します。
SaplingではなくOrchard
Orchardが選ばれたのは、そのアクション回路が単一の証明内で任意の数の入力と出力を柔軟にサポートするためです。pERC20バンドルは、複数の消費と出力を1つのトランザクションに結合できます。Saplingの固定された1入力/2出力のアクション形状では、人為的な分割、高いリレーヤーコスト、およびマルチノート転送のUXの低下を余儀なくされます。
Halo2 / PLONKではなくGroth16
EVM上でのGroth16検証コストは、同等のセキュリティレベルで一般的なHalo2またはPLONK検証者よりも低いです。ペアリングベースのGroth16チェッカーはオンチェーンでよく理解されています。VKサイズと検証者バイトコードは、アセットごとのデプロイメントに実用的であり、アクションごとのガスを予測可能に保ちます。
回路内のコンプライアンスルート(cmxFrozenRoot)
コンプライアンスブラックリストは、cmxFrozenRootをルートとする**cmx(ノートコミットメント)のセットです。ユーザーが使用する際、オンチェーンアクションは消費されたノートのcmxではなく、nfOld(nullifier)を公開します。オンチェーンには、nullifierからcmxへの直接的でプライバシーを保護するマッピングは存在しない**ため、コントラクトはプライバシーを侵害することなく「このnullifierは凍結されたコミットメントに紐付けられているか?」を安価にチェックすることはできません。
したがって、制約は回路内で強制されます。証明者は、消費されたノートのコミットメントがpubFields[7] == cmxFrozenRoot()をルートとするブラックリストSMTのメンバーではないことを示します(非メンバーシップ証明)。チェーンはSMTルートのみを保存しバインドします。メンバーシップロジックはZK内に留まります。これは明示的なトレードオフです。特定されたノートに対するコンプライアンスは厳密に保証されますが、回路とcmxFrozenRootを更新する管理者を信頼する必要があります。
エコシステム統合(非規範的)
pERC20は、より広範なプライバシー転送インフラストラクチャを補完することを意図しています。考えられるエコシステムパスの1つは次のとおりです。
- 既存の公開アセット(DeFi関連アセットを含む)は、プロトコルレベルのプライベート転送インフラストラクチャを通じてプライベート転送パスを獲得します。
- プライバシーネイティブなアセットとノートは、新しいアプリケーション設計のための第一級のプリミティブになります。
- 新しいプロトコルカテゴリは、プライバシーを周辺的なラッパーとして扱うのではなく、プライバシーネイティブな状態に直接構築されます(例えば、プライバシー保護された交換、貸付、または構造化された決済フロー)。
この提案は、ブリッジ構築、リレーヤー経済学、プライベートメムプール/ネットワークの仮定、またはプライベートオラクル設計を標準化するものではありません。その範囲は、プライバシーネイティブなファンジブルアセットのトークンインターフェースセマンティクスと不変条件に限定されます。
後方互換性
pERC20は、ERC-20のbalanceOf、approve、allowance、またはtransferFrom(from, to, amount)を実装しないため、既存のERC-20ツールで直接使用することはできません。
| ERC-20 | pERC20 | 注記 |
|---|---|---|
| name / symbol / decimals | 同じ | 公開メタデータ |
| totalSupply | totalSupply | 公開 |
| balanceOf(addr) | なし | 残高はプライベート。保有者はIVK/FVKを介してスキャン |
| transfer(to, amount) → bool | transfer(PrivacyCall) → bool | 当事者と金額はプライベート。戻り値の規約は保持 |
| transferFrom / approve / allowance | なし | 承認する公開残高なし。ビューイングキーを介した委任 |
| 発行 (拡張) | mint(amount, PrivacyCall) | 発行者のみ |
| 焼却 (拡張) | burn(amount, PrivacyCall) | どの保有者も可能 |
| Transfer / Approval イベント | Transferは省略。ノートごとはNoteAdded / NoteConfirmedを介して。供給はMint / Burnを介して | IDはリンク不可 |
公開DeFiとの相互運用性は、オプションのbridgeOut(pERC20 → 公開ERC-20ツイン)を介して達成MAYできます。この場合、プライバシーは出口で終了します(この提案では必須ではありません)。
テストケース
参照実装 (PERC20Labs/PERC20) には以下が含まれます。
- コンストラクタガード、発行/焼却/転送会計、および供給不変条件のためのFoundry単体テスト(
test/PERC20Test.t.sol)。 - 実際のGroth16証明を生成し、デプロイされた
PERC20コントラクトに対して発行、転送、焼却を実行するモックなしのエンドツーエンドスイート(test/PERC20E2E.t.sol,e2e/)。
シナリオから仕様へのマッピングと調査結果については、そのリポジトリのdocs/e2e-report.mdを参照してください。
参照実装
参照実装: PERC20Labs/pERC20_ (最小限の参照アセットコントラクト)。
- 規範的なアセットコントラクト: そのリポジトリの
contracts/ptoken/PERC20.sol(IPERC20参照)。
PERC20はOrchardVerifier(IEndpointCore)を継承し、完全な参照実装からのGroth16検証者、マークルコミットメントツリー、および暗号ライブラリに依存しています。
セキュリティに関する考慮事項
- 二重使用防止: nullifierセットと回路内の正しい
nf導出に依存します。isSpentが設定されたら、ノートは再度使用可能であってはなりませんMUST NOT。pubFieldsのフィールド範囲チェック(< Fr)は二重使用防止の前提条件です。そうでなければ、nf + Frは同じ証明を再利用しつつisSpentをバイパスできます(データ構造を参照)。 - 供給不変条件:
totalSupply会計を持つアセットコントラクトは、値の変更を発行 / 焼却 / 転送を通じてのみ公開MUSTします。コア実行パスは公開呼び出し可能であってはなりませんMUST NOT。そうでなければ、誰でもtotalSupplyを増加させることなく、未計上の値を注入できてしまいます。 - 値の保存: バインディング署名とNUMSジェネレーター(
log_{G_RANDOM}(G_VALUE)は不明)に依存します。amountとvalueBalance間の一貫性は、下位255ビットを比較することで強制されます。署名ポイントRは曲線およびフィールドの検証MUSTを受けなければなりません。 - リプレイ保護: sighashドメイン分離は、
[[glossary/chainId|chainId]]、コントラクトアドレス、およびすべてのnf/cmx値をバインドし、クロスチェーン、クロスコントラクト、およびクロスバンドルのリプレイを防ぎます。 - アンカーの有効性:
isValidAnchorは永続的なセットを使用するため、古い証明アンカーは有効なままですが、決して生成されなかったルートの偽造を防がなければなりませんMUST。 - コンプライアンス権限のリスク: 管理者(発行者 / コンプライアンス担当者)は
setFrozenRootを介してノートを凍結できます。これは高価値の攻撃対象であり、信頼された役割です。マルチシグ / タイムロックを使用SHOULDし、FrozenRootUpdatedログは公開SHOULDされるべきです。デプロイメントでは通常、コンプライアンスとアセット管理の両方を構築時に同じ管理者に割り当てます。分離が必要な実装は、管理者を独立したコンプライアンスマルチシグに転送SHOULDします。 - 管理者権限:
setGroth16Verifier、transferAdmin+acceptAdmin、およびsetMaxActionsは検証ロジックとパラメータを変更できます。ガバナンスによって制約されるSHOULDです(マルチシグ + タイムロック)。検証者をローテーションする際、新しい検証者のActionPubHashは回路と一致MUSTします。2段階の管理者転送は偶発的なロックアウトを防ぎます。
プライバシーに関する考慮事項
- 受信者の匿名性: 操作はリレーヤーを介して提出SHOULDされ、提出者の外部所有アカウント (EOA)を隠します。直接の自己提出はEOAを操作にリンクさせます。
- 金額の可視性: 発行 / 焼却の
amountとtotalSupplyは公開です。転送量はプライベートです。 - 匿名セット: アセットごとのプールは、新しいアセットが小さな匿名セットから始まることを意味します。クロスアセット共有匿名性(共有ツリー +
asset_id)は、回路の変更を必要とする将来の強化です。 - コンプライアンス vs. プライバシー:
cmxFrozenRootメカニズムは特定された特定のノートを凍結できますが、(a)cmxの特定には通常、ビューイングキーの開示またはオフチェーンのインテリジェンスが必要であり、(b) ターゲットノートが凍結前に転送された場合、値は新しいcmxに移動し、再特定が必要になります。強制的なコンプライアンスルートは明示的な設計選択です。実装は、cmxFrozenRoot == 0(空のブラックリスト = デフォルトで許可)を維持して、トラストレス性を近似MAYできます。
1投稿 - 1参加者