# intmax operator 旧仕様 (PlonK 版)
intmax の operator 側の仕様について,
account や transaction の表現方法などを記載しています.
## Notation
$\mathbb{N}$ は 0 以上の整数全体からなる集合, $\mathbb{N}_{m} := [0, 2^m - 1]$ $(m > 1)$ は $m$ bits で表せる数値全体からなる集合, $\mathbb{B}_{n}$ $(n \geq 1)$ はちょうど $n$ bytes のバイト列全体からなる集合, $\mathbb{B} = \bigcup_{n = 0}^{\infty} \mathbb{B}_{n}$ は任意の長さのバイト列全体からなる集合とする.
$\mathbb{F}_r$ は位数 $r$ の有限体とする. $E$ は楕円曲線, $E(\mathbb{F}_r)$ は $E$ の $\mathbb{F}_r$ 有理点全体からなる集合とする. $E(\mathbb{F}_r)$ 上の二項演算 $+$ をうまく定めることにより, $E$ の無限遠点 $\mathcal{O}_{E}$ を単位元とする可換群の構造が入る.
楕円曲線 $E(\mathbb{F}_r)$ には素数位数 $s$ の元 $B$ が存在するとし, $B$ が生成する巡回群を $\langle B \rangle := \{ B, 2B, \ldots, (s-1)B, sB = \mathcal{O}_{E} \}$ で表す. その任意の元 $G \in \langle B \rangle$ は,
$$
sG = \mathcal{O}_{E}
$$
をみたす. $E(\mathbb{F}_r)$ の元は, (Reduced) Twisted Edwards Form の場合, $\mathbb{F}_r^2 \cup \{ \mathcal{O}_{E} \}$ の元として表現できる.
集合 $X, Y$ について, 対応 $f: X \to Y$ としてあり得るもの全体の集まりを $\mathsf{Map} [X, Y]$ で表す.
<!-- value が $\mathbb{F}_r$ の元であるような深さ $n$ の Merkle tree 全体からなる集合を $\mathsf{MT}_n$ と表す.
$\mathsf{Map} [2^n, \mathbb{F}_r]$
-->
<!-- key, value がともに $\mathbb{F}_r$ の元であるような sparse Merkle tree (SMT) 全体からなる集合を $\mathsf{SMT}$ と表す. -->
<!-- 例えば, 集合 $\mathsf{MT}_1$ には $\{ (0, v_0), (1, v_1) \}$ という 2 つの leaf を持った Merkle tree が属する. -->
<!-- 全ての key に $0 \in \mathbb{F}_r$ が格納されている Merkle tree を $\mathbf{0}$ と表す. また, SMT のいくつかの key に対応する値は存在しないことがある (そのことを記号 $\bot$ で表す). どの key に対応する値も持たない SMT は**空**であると呼び, 空集合と同じ記号 $\emptyset$ で表すことにする. 空である SMT の root hash は $0 \in \mathbb{F}_r$ とする. -->
SMT の leaf に別の SMT の root hash が含まれるような 2 層の SMT を **layered SMT** と呼ぶことにする.
<!-- このとき, key が 2 つの $\mathbb{F}_r$ の元の組で表される. このような layered SMT 全体からなる集合を
$$
\mathsf{LSMT} := \mathsf{Map} [\mathbb{F}_r \times \mathbb{F}_r, \mathbb{F}_r \cup \{ \bot \}]
$$
と表す. -->
## Setup (Operator)
operator は次の 4 つの (sparse) Merkle tree を扱う.
$$
\mathtt{commonly\_shared\_storage} \leftarrow \emptyset \in \mathsf{Map} [\mathbb{F}_r, \mathbb{F}_r \cup \{ \bot \}]
$$
`user_asset_storage` は `contract_address` に対応する `internal_user_asset_root` を格納する SMT.
$$
\mathtt{user\_asset\_storage} \leftarrow \emptyset \in \mathsf{Map} [\mathbb{F}_r, \mathbb{F}_r \cup \{ \bot \}]
$$
`contract_asset_storage` は `contract_address` と `variable_index` に対応する値を格納する layered SMT.
$$
\mathtt{contract\_asset\_storage} \leftarrow \emptyset \in \mathsf{Map} [\mathbb{F}_r, \mathsf{Map} [\mathbb{F}_r, \mathbb{F}_r \cup \{ \bot \}]]
$$
`asset_diff_storage` は `tx_hash` に対応する `asset_diff_root` を格納する SMT.
$$
\mathtt{asset\_diff\_storage} \leftarrow \emptyset \in \mathsf{Map} [\mathbb{F}_r, (\mathbb{F}_r \times \mathbb{F}_r) \cup \{ \bot \}]
$$
また, これらの Merkle tree root をまとめた `world_state_root` を初期化する.
$$
\mathtt{world\_state\_root} \leftarrow \mathbf{Poseidon}_{4}(0, 0, 0) \in \mathbb{F}_r$$
operator はこれらを常に記憶し, user からの要求に応じて更新する. state tree の詳細は Appendix で説明している.
## Setup (User)
user は適切な方法で秘密鍵を生成する.
$$
\mathtt{user\_private\_key} \overset{$}{\leftarrow} \mathbb{F}_s
$$
この秘密鍵はトランザクションを生成する際に毎回必要となり, 他者に教えてはならない. この秘密鍵を用いて自身のアカウント (`user_account`) を用意する. (address を連番の登録制にする方向性もあり)
$$
\mathtt{user\_public\_key} \leftarrow \mathbf{PrvToPub}( \mathtt{user\_private\_key}) \in \langle B \rangle \subset E(\mathbb{F}_r) \\
\mathtt{user\_address} \leftarrow \mathbf{PubToAddr}( \mathtt{user\_public\_key}) \in \mathbb{B}_{20}, \\
\mathtt{user\_nonce} \leftarrow 0 \in \mathbb{N}_{64} \\
\mathtt{user\_account} = (\mathtt{user\_private\_key},
\mathtt{user\_public\_key}, \\ \mathtt{user\_address}, \mathtt{user\_nonce})
$$
さらに, user は自身の state を管理するための layered SMT を保持しておく.
$$
\mathtt{internal\_user\_asset\_storage} \leftarrow \emptyset \in \mathsf{Map} [\mathbb{B}_{20}, \mathsf{Map} [\mathbb{F}_r, \mathbb{F}_r \cup \{ \bot \}]]
$$
one-time account は今回使用しないので, 通常の account と同じとする.
$$
\mathtt{ot\_private\_key} = \mathtt{user\_private\_key}, \\
\mathtt{ot\_public\_key} = \mathtt{user\_public\_key}, \\
\mathtt{ot\_address} = \mathtt{user\_address}
$$
## Transaction
まず, 全体の処理を通してみると, 次のようになっている.
```mermaid
sequenceDiagram
User->>OneTimeAccount: tx, nonce
OneTimeAccount->>Operator: signed_tx
Operator->>Operator: calc_state_diff
Operator->>OneTimeAccount: user_asset_diff
OneTimeAccount->>User: user_asset_diff
User->>User: merge_user_asset <br /> & sign_diff
User->>Operator: signed_tx, internal_user_state_root, signed_user_asset_diff
Operator->>Operator: update_user_state & <br /> merge_shared_state
```
transaction は下記の要素から構成される(本当は one-time account で署名するが, 今回は user の通常の鍵で署名する).
$$
\mathtt{tx} = (
\mathtt{ot\_public\_key},
\mathtt{user\_nonce}, \\
\mathtt{contract\_address},
\mathtt{function\_signature},
\mathtt{calldata})
$$
ただし,
$$
\mathtt{contract\_address} \in \mathbb{B}_{20}, \\
\mathtt{function\_signature} \in \mathbb{B}_{4}, \\
\mathtt{user\_nonce} \in \mathbb{N}_{64}, \\
\mathtt{calldata} \in \mathbb{B}
$$
transaction の digest は Poseidon hash で計算する. ただし, $(c_0, \ldots, c_3) \in (\mathbb{B}_{32})^4$ は `calldata` を 128 bytes になるように右側を 0 パディングし, 32 bytes ごとに分割したものである.
$$
\mathtt{nonce\_address\_sig} \leftarrow \mathbf{ToFr}(\mathtt{user\_nonce} \| \mathtt{contract\_address} \| \\ \mathtt{function\_signature}) \in \mathbb{F}_{r}
$$
ただし, `to_fr` はバイト列を Big Endian で $\mathbb{F}_{r}$ 型に変換する.
> `user_nonce` の上位 3 bits は無視されるが, nonce は連番で使用されるため, 問題ないと考えている.
$$
\mathtt{tx\_hash} \leftarrow \mathbf{Poseidon}_6(\mathtt{nonce\_address\_sig}, c_0, c_1, c_2, c_3) \in \mathbb{F}_r \\
$$
これに署名する.
$$
\mathtt{tx\_signature} \leftarrow \mathbf{SignEddsaPoseidon}(\mathtt{ot\_private\_key}, \\
\mathtt{tx\_hash}) \in \mathsf{Signature}
$$
ここで, $\mathsf{Signature}$ は
$$
\mathsf{Signature} := \{ (R, S) \mid R \in E(\mathbb{F}_r), S \in \mathbb{F}_s \}$$
なる集合を表す.
$$
\mathtt{signed\_tx} = (\mathtt{tx}, \mathtt{tx\_hash}, \mathtt{ot\_public\_key}, \mathtt{tx\_signature})
$$
を operator に送信する.
> 事前に残高を減らすようなマージが行われていることを証明しなければならない.
## Diff
operator は受け取った transaction の内容を見て, user asset storage の変化 `asset_diff` を計算する. 変更があるすべての state について, contract address, variable index の組とそれに対応する差分 `asset_diff` を列挙する.
$$
\mathtt{world\_state\_diff} \leftarrow \mathbf{CalcTransition}(\mathtt{tx}) \in \mathsf{WorldStateDiff}
$$
$$
\mathsf{WorldStateDiff} := \mathsf{SharedStateDiffList} \times \\
\mathsf{UserAssetDiffList} \times \mathsf{ContractAssetDiffList}
$$
$$
\mathsf{SharedStateDiffList} := \mathsf{Map}[\mathbb{B}_{20} \times \mathbb{F}_r, \mathbb{F}_r] \\
\mathsf{UserAssetDiffList} := \mathsf{Map}[\mathbb{B}_{20} \times \mathbb{B}_{20} \times \mathbb{F}_r, \mathbb{F}_r] \\
\mathsf{ContractAssetDiffList} := \mathsf{Map}[ \mathbb{F}_r, \mathbb{F}_r]
$$
`world_state_diff` の各要素をそれぞれ, `shared_state_diff`, `user_asset_diff`, `contract_asset_diff` とする.
`world_state_diff` の digest を SMT で作る.
$$
\mathtt{world\_state\_diff\_root} \leftarrow \mathbf{Commit}_{\mathsf{SMT}}(\mathtt{world\_state\_diff}) \in \mathbb{F}_r
$$
operator は `diff_storage` に `(key, value) = (tx_hash, world_state_diff_root)` というエントリを追加して, その commitment `world_state_diff_root` と `transaction` 及び `world_state_diff` をどこか安全な場所に公開する.
$$
\mathtt{diff\_storage} \leftarrow \mathbf{Insert}(\mathtt{diff\_storage}, \\
(\mathtt{tx\_hash}, \mathtt{world\_state\_diff\_root}))
$$
> 並行処理は難しそう.
operator はこの `world_state_diff` (と `world_state_diff_root`) を user に送信する.
user は operator から渡された `world_state_diff` に含まれる `user_asset_diff` のうち自身に関わるものと (必要であればまだ反映していない diff) によって自身の user asset storage を更新し, transaction を取り込んだことを保証する.
> user は `world_state_diff` に含まれる `user_asset_diff` のうち自身に関わるものの commitment `user_asset_diff_root` に署名する.
> 他人 `receiver` の asset を増加させる差分 `receiver_asset_diff` は sender が直接渡してあげ, それが全体の `asset_diff` の一部であることの inclusion-proof もする. `receiver` はそれをマージして署名を operator に提出し, sender の `asset_diff` への commitment と合わせて token を受け取ったことになる.
`user_state_diff` に従って, user は自身で管理している internal user asset storage を更新して, internal user asset storage の layered SMT root `internal_user_asset_root` を operator に送信する.
$$
\mathtt{internal\_user\_asset\_storage} \leftarrow \mathbf{Merge}(\mathtt{internal\_user\_asset\_storage}, \\ \mathtt{asset\_diff}) \\
\mathtt{internal\_user\_asset\_root} \leftarrow \mathbf{Commit}_{\mathsf{LSMT}}(\mathtt{internal\_user\_asset\_storage})
$$
さらに, user は `world_state_diff_root` に署名して operator に送信する.
$$
\mathtt{diff\_signature} \leftarrow \mathbf{SignEddsaPoseidon}(\mathtt{user\_private\_key}, \\
\mathtt{world\_state\_diff\_root}) \in \mathsf{Signature} \\
\mathtt{signed\_diff} = (\mathtt{world\_state\_diff}, \mathtt{world\_state\_diff\_root}, \\
\mathtt{user\_public\_key}, \mathtt{diff\_signature})
$$
> なぜ, user は asset diff に署名してそれを見たことを operator に納得させないといけないのか? これをしない場合, exit 時の user asset storage がどこまでの差分を既にマージした状態なのかがわからなくなる.
operator は user asset storage, contract asset storage, commonly shared storage をそれぞれ更新する.
> 複数人の update を一定期間受け付ける. 理想的には 5 秒間隔.
$$
\mathtt{user\_state\_storage} \leftarrow \mathbf{Update}(\mathtt{user\_state\_storage}, \\
(\mathtt{user\_address}, \mathtt{user\_asset\_root}))
\\
\mathtt{contract\_asset\_storage} \leftarrow \mathbf{Merge}(\mathtt{contract\_asset\_storage}, \\
\mathtt{contract\_state\_diff})
\\
\mathtt{commonly\_shared\_storage} \leftarrow \mathbf{Merge}(\mathtt{commonly\_shared\_storage}, \\
\mathtt{shared\_state\_diff})
$$
> それと同時に `signed_diff` を保管する. (不要?)
operator は world state を更新し, 公開する.
$$
\mathtt{world\_state\_root} \leftarrow \mathbf{Poseidon}_{4}( \\
\mathbf{Commit}_{\mathsf{LSMT}}(\mathtt{user\_asset\_storage}), \\
\mathbf{Commit}_{\mathsf{LSMT}}(\mathtt{contract\_asset\_storage}), \\
\mathbf{Commit}_{\mathsf{SMT}}(\mathtt{commonly\_shared\_storage}))
$$
user asset root から world state root までの Merkle proof を user に渡す. ただし, user が online でない場合, 一時的なストレージ (ERC4844 Shard Blob) に保管する.
## Rollup
> rollup について
## Exit
> exit について
## Appendix
### JSON
$\mathbb{N}_{m}$ や $\mathbb{B}_{n}$ の元は原則 `0x` 接頭辞がついた 16 進数 (hex) 文字列として扱う. $\mathbb{F}_r$ も普通の 256 bits 数値 $\mathbb{N}_{256}$ と見做して扱う. 楕円曲線上の点 $G \in E(\mathbb{F}_r)$ は $\mathtt{compress\_point}(G)$ によって 256 bits 数値 $\mathbb{N}_{256}$ と見做す.
$\mathtt{user\_asset\_diff} \in \mathsf{StateDiffList}$ の serialize は, $\mathtt{diff} := \mathtt{user\_asset\_diff}[x] \neq 0$ なる全ての $x = ( \mathtt{contract\_address}, \mathtt{variable\_index}) \in \mathbb{B}_{20} \times \mathbb{F}_r$ について,
連想配列 `{ address: contract_address, key: variable_index, diff: diff }` を(順序を気にせず)列挙した配列として扱う. 例えば,
`user_asset_diff.get(("0x00...00", 1)) == 10`, `user_asset_diff.get(("0x00...00", 3)) == -20` であり, その他の差分が 0 の場合,
```
[
{
address: "0x0000000000000000000000000000000000000000",
key: 1,
diff: 10
},
{
address: "0x0000000000000000000000000000000000000000",
key: 3,
diff: -20
}
]
```
となる.
### Account
鍵を生成するための楕円曲線は, Alt BabyJubjub BN-256 ([EIP 2494](https://eips.ethereum.org/EIPS/eip-2494#generator-point)) を採用し, 次のパラメータを用いる.
$E: a^{\prime}x^2 + y^2 = 1 + d^{\prime}x^2y^2$ (Reduced Twisted Edwards Form)
`d' = 0x1aee90f15f2189693df072d799fd11fc039b2959ebb7c867d075ca8cf4d7eb8e`
`a' = -1`
`r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001`
`s = 0x60c89ce5c263405370a08b6d0302b0bab3eedb83920ee0a677297dc392126f1`
base point としては次の元が選ばれている.
```md
# Reduced Twisted Edwards Form
B = (
0x1561ff836ce19d358a4eb7a4c199e94c377c749ae6f2a277f1f9195afe553f9f,
0x25797203f7a0b24925572e1cd16bf9edfce0051fb9e133774b3c257a872d7d8b
)
# Twisted Edwards Form
B = (
0xbb77a6ad63e739b4eacb2e09d6277c12ab8d8010534e0b62893f3f6bb957051,
0x25797203f7a0b24925572e1cd16bf9edfce0051fb9e133774b3c257a872d7d8b
)
```
また, この楕円曲線 $E(\mathbb{F}_r)$ は位数 $8s$ の元 $G_0$ をもち, $B = 8G_0$ が成り立っている.
> それゆえ, $B$ には `base8` という変数名がついている.
<!-- EdDSA 署名には, このような $2^c s$ ($c$ は正整数, $s$ は十分に大きい素数) の形の位数を持つような曲線が選ばれる[[2](https://ed25519.cr.yp.to/ed25519-20110926.pdf)]. -->
```md
# Reduced Twisted Edwards Form
G0 = (
0x0b068376907718bbf713937de82f368c0f049cdf93d705e8294891fba133936f,
0x0c19139cb84c680a6e14116da06056174a0cfa121e6e5c2450f87d64fc000001
)
# Twisted Edwards Form
G0 = (
0x023343e3445b673d38bcba38f25645adb494b1255b1162bb40f41a59f4d4b45e,
0x0c19139cb84c680a6e14116da06056174a0cfa121e6e5c2450f87d64fc000001
)
```
#### CompressPoint
input: `point`
output: `compressed_form`
楕円曲線上の点を twisted Edwards form の圧縮形式に変換する.
$$
G \leftarrow \mathtt{point} \in E(\mathbb{F}_r) \backslash \{ \mathcal{O}_{E} \} \\
(g_x, g_y) \leftarrow \mathbf{ToTwistedEdwardsForm}(G) \in \mathbb{F}_r \times \mathbb{F}_r \\
\sigma_{x} \leftarrow \mathbf{IsOdd}(g_x) \in \{ 0, 1 \} \\
\mathtt{compressed\_form} \leftarrow \sigma_{x} \cdot 2^{255} + g_y \in \mathbb{N}_{256}
$$
#### CurveToHash
input: `point`
output: `hash`
楕円曲線上の点から、その定義体上のハッシュを得る.
$$
G \leftarrow \mathtt{point} \in E(\mathbb{F}_r) \backslash \{ \mathcal{O}_{E} \} \\
(g_x, g_y) \leftarrow \mathbf{ToTwistedEdwardsForm}(G) \in \mathbb{F}_r \times \mathbb{F}_r \\
\mathtt{hash} \leftarrow \mathbf{Poseidon}_{3}(g_x, g_y) \in \mathbb{F}_r
$$
#### HashPriv
input: `private_key`
output: `new_private_key`
秘密鍵をハッシュして新しい秘密鍵を得る.
$$
a \leftarrow \mathtt{private\_key} \in \mathbb{F}_{s} \\
a_{1} \leftarrow \mathbf{Sha256}(a) \in \mathbb{B}_{32} \\
a_{2} \leftarrow \mathbf{ToLE}(a_{1}) \in \mathbb{N} \\
a_{2}[31] \leftarrow a_{2}[31] \operatorname{and} \mathtt{0x7F} \\
a_{2}[31] \leftarrow a_{2}[31] \operatorname{xor} \mathtt{0x40} \\
\mathtt{new\_private\_key} \leftarrow \left\lfloor \frac{a_{2}}{8} \right\rfloor \mod s
$$
#### PrivToPub
input: `private_key`
output: `public_key`
秘密鍵から対応する公開鍵を得る.
$$
a = \mathbf{HashPriv}(\mathtt{private\_key}) \in \mathbb{F}_s \\
A \leftarrow a \cdot B \\
\mathtt{public\_key} \leftarrow \mathtt{compress\_point}(A) \in \mathbb{B}_{32}
$$
#### PubToAddr
input: `public_key`
output: `address`
EdDSA の公開鍵と一意に対応する 20 bytes の文字列(アドレス)を得る.
$$
A = \mathbf{DecompressPoint}(\mathtt{public\_key}) \in \langle B \rangle \subset E(\mathbb{F}_r) \\
\mathtt{address} \leftarrow \mathbf{ToLSB}_{160}(\mathbf{CurveToHash}(\mathtt{public\_key}))
$$
> 回路内で address を計算するコストが高いので, address の代わりに hashed public key をそのまま使うか, user ID を連番で割り当てることになりそう.
#### SignEddsaPoseidon
input: `private_key`, `msg`
output: `sig`
秘密鍵 `private_key` を用いてメッセージ `msg` に署名する. 後述する `verify_eddsa_poseidon` で検証することができる.
$$
m \leftarrow \mathtt{msg} \in \mathbb{F}_{r} \\
a \leftarrow \mathbf{HashPriv}(\mathtt{private\_key}) \\
A \leftarrow \mathbf{PrivToPub}(\mathtt{private\_key}) \\
d \leftarrow \mathbf{Sha256}(a \| m) \in \mathbb{B}_{32} \\
r \leftarrow \mathbf{ToLE}(\mathtt{seed}) \mod s \\
R \leftarrow r \cdot B \\
(R_x, R_y) \leftarrow \mathbf{ToTwistedEdwardsForm}(R) \\
(A_x, A_y) \leftarrow \mathbf{ToTwistedEdwardsForm}(A) \\
h \leftarrow \mathbf{Poseidon}_{6}(R_x, R_y, A_x, A_y, m) \\
\sigma \leftarrow 8ha + d \\
\mathtt{sig} = (R, \sigma)
$$
#### VerifyEddsaPoseidon
input: `sig`, `public_key`
output:
`sign_eddsa_poseidon` によって作られた署名 `sig` が `public_key` に対応する秘密鍵を持つアカウントによって作成されたものであることを検証する.
$$
(R, \sigma) \leftarrow \mathtt{sig} \\
A \leftarrow \mathtt{public\_key} \\
(R_x, R_y) \leftarrow \mathbf{ToTwistedEdwardsForm}(R) \\
(A_x, A_y) \leftarrow \mathbf{ToTwistedEdwardsForm}(A) \\
h \leftarrow \mathbf{Poseidon}_{6}(R_x, R_y, A_x, A_y, m) \\
\mbox{Check } 8A \neq \mathcal{O}_{E} \\
\mbox{Check } \sigma \cdot B = 8hA + R
$$
### Transaction
#### NFT の送信
ID が `token_id` の NFT を `sender_address` が所持している場合、 それを `receiver address` に移動する. `function_signature = 1` (番号は変更の可能性あり)
calldata は全部で 96 bytes のバイト列であり,
$$
\mathtt{calldata} \leftarrow \mathtt{sender\_address} \|
\mathtt{receiver\_address} \| \mathtt{token\_id} \in \mathbb{B}_{96}
$$
$$
\mathtt{sender\_address} \in \mathbb{B}_{20}, \\
\mathtt{receiver\_address} \in \mathbb{B}_{20}, \\
\mathtt{token\_id} \in \mathbb{F}_r
$$
とする. ただし, 全ての要素を 32 bytes の Big Endian になるように左側 0 padding する. 例えば,
`sender_address = 0x86f616f870b89668e6021b0b6070a9234a236c50`,
`receiver_address = 0xe7b7e03eb0af47f303cf33707d755cdd9fc22a9f`,
`token_id = 1` の場合,
`calldata = 0x00000000000000000000000086f616f870b89668e6021b0b6070a9234a236c50000000000000000000000000e7b7e03eb0af47f303cf33707d755cdd9fc22a9f0000000000000000000000000000000000000000000000000000000000000001`
となる.
#### NFT の発行
`minter` の権限をもつアカウントが自分自身に既出でない ID の NFT を発行する. `function_signature = 2` (番号は変更の可能性あり)
calldata は全部で 32 bytes のバイト列であり,
$$
\mathtt{calldata} \leftarrow \mathtt{token\_id} \in \mathbb{B}_{32}
$$
とする. 例えば, `token_id = 1` の場合,
`calldata = 0x0000000000000000000000000000000000000000000000000000000000000001`
となる.
#### NFT コントラクトのデプロイ
(未実装) NFT contract の template 番号 `template_id = 2` を指定して, deployer の address をもとに適切に生成された contract address にデプロイする.
### State Tree Model
全体を俯瞰すると, 次のようになっている.
```mermaid
graph TB
subgraph world state MT
A(0x7713)-- 0 --->B(0x4092)
A-- 1 --->BB(0x1727)
A-- 2 --->C(0x8335)
end
C-.-C2
subgraph shared state Layered SMT
C2(0x8335)-- 0 --->E(0x2590)
C2-- 1 --->G(key: 5, value: 28)
E-- 0 --->N(key: 8, value: 92)
E-- 1 --->O(key: 10, value: 48)
end
BB-.-BB2
subgraph CA state SMT
BB2(0x1727)-- 0 --->DD(0x7438)
DD-- 0 --->HH(address: 4, value: 0x1926)
DD-- 1 --->II(address: 6, value: 0x9427)
end
B-.-B2
subgraph user state SMT
B2(0x4092)-- 0 --->D(0x3847)
D-- 0 --->H(address: 4, value: 0x1926)
D-- 1 --->I(address: 6, value: 0x9427)
end
II-.-II4
subgraph CA asset SMT
II4(0x9427)-- 0 --->QQ(key: 10, value: 4)
II4-- 1 --->RR(0x6361)
RR-- 0 --->SS(key: 5, value: 73)
RR-- 1 --->TT(key: 3, value: 17)
end
HH-.-HH4
subgraph CA asset SMT
HH4(0x1926)-- 0 --->PP(key: 8, value: 17)
end
I-.-I4
subgraph user asset Layered SMT
I4(0x9427)-- 0 --->Q(key: 10, value: 4)
I4-- 1 --->R(0x6361)
R-- 0 --->S(key: 5, value: 73)
R-- 1 --->T(key: 3, value: 17)
end
H-.-H4
subgraph user asset Layered SMT
H4(0x1926)-- 0 --->P(key: 8, value: 17)
end
```
<!-- storage と tree との関係
- shared state SMT は Commonly Shared Storage から構成される.
- contract asset SMT は CA Asset Storage から構成される.
- user asset SMT は User Asset Storage から構成される. -->
#### world state MT
leaf を 3 つだけもつ Merkle tree.
key 0 に対応する値は user state SMT の root hash (in $\mathbb{F}_r$), key 1 に対応する値は CA state SMT の root hash, key 2 に対応する値は shared state SMT の root hash (in $\mathbb{F}_r$) を表す.
```mermaid
graph TB
subgraph world state MT
A(0x7713)-- 0 --->B(0x4092)
A-- 1 --->BB(0x1727)
A-- 2 --->C(0x8335)
end
```
#### shared state SMT
Commonly Shared Storage から構成される layered SMT.
key は `contract address` と `variable index` の組, value はその contract address と variable index の組に対して格納された値 (in $\mathbb{F}_r$) を表す.
ただし, key `(address, 0)` には, 実行コードの template number が格納され, これが 0 でない場合にはそのアドレスはコントラクトと見做される.
```mermaid
graph TB
subgraph shared state SMT
C2(0x8335)-- 0 --->E(0x2590)
C2-- 1 --->G(key: 5, value: 28)
E-- 0 --->N(key: 8, value: 92)
E-- 1 --->O(key: 10, value: 48)
end
```
#### contract asset SMT
CA Asset Storage から構成される SMT.
key は variable index (in $\mathbb{F}_r$), value はそこに格納された値 (in $\mathbb{F}_r$) を表す.
#### user state SMT
key は user address (in $\mathbb{B}_{20}$), value は user asset SMT の root hash (in $\mathbb{F}_r$) を表す.
```mermaid
graph TB
subgraph user state SMT
B2(0x4092)-- 0 --->D(0x3847)
D-- 0 --->H(address: 4, value: 0x1926)
D-- 1 --->I(address: 6, value: 0x9427)
end
```
#### internal user state MT (仮名称)
leaf を 2 つだけもつ Merkle tree.
key 0 に対応する値は state diff SMT の root hash (in $\mathbb{F}_r$), key 1 に対応する値は user asset SMT の root hash (in $\mathbb{F}_r$) を表す.
```mermaid
graph TB
subgraph internal user state MT
I1(0x9427)-- 0 --->I2(0x8218)
I1-- 1 --->I3(0x4573)
end
```
#### user asset SMT
User Asset Storage から構成される layered SMT.
key は `contract address` と `variable index` の組, value はその contract address と variable index の組に対して格納された値 (in $\mathbb{F}_r$) を表す. この state tree は user が保管し, トランザクションを送信したり L2 から exit する際に必要になる.
```mermaid
graph TB
subgraph user asset SMT
I4(0x4573)-- 0 --->Q(key: 10, value: 4)
I4-- 1 --->R(0x6361)
R-- 0 --->S(key: 5, value: 73)
R-- 1 --->T(key: 3, value: 17)
end
```
#### state diff SMT
key は nonce (in $\mathbb{N}_{64}$), value は nonce に対応する user asset diff SMT の root hash (in $\mathbb{F}_r$) を表す.
```mermaid
graph TB
subgraph state diff SMT
I5(0xc932)-- 0 --->I6(nonce: 0, value: 0x8218)
end
```
#### user asset diff SMT
各トランザクションで発生する user account の asset 変動のみを格納した SMT.
key は contract address と variable index の Poseidon hash (in $\mathbb{F}_r$), value はその contract address と variable index の組に対して格納された値の変化量 (in $\mathbb{F}_r$) を表す.
```mermaid
graph TB
subgraph user asset diff SMT
U(0x8218)-- 0 --->V(key: 10, diff: +1)
U-- 1 --->W(0x1414)
W-- 0 --->X(key: 5, diff: -20)
W-- 1 --->Y(key: 3, diff: +10)
end
```
#### shared state diff SMT
トランザクションで発生する shared state の変化のみを格納した SMT. 構造は user asset diff SMT と同様.
#### contract asset diff SMT
トランザクションで発生する contract account の asset 変動のみを格納した SMT. 構造は user asset diff SMT と同様.
## Comments
last block はどこに書く?
差分は state tree の中には<s>いらない. user asset はマージした状態で渡し, なぜちゃんとマージできているかを確認するには ZKP を使う.</s>いる.
最後の tx が取り込まれたことを確認する方法として, address は user ID にする (登録制), その時の user state root と id list (user ID と last block) の inclusion proof. onchain cost を減らすための ID.
NFT を受け取るためには
- online にいる (この場合, 手数料を安く利用できるようにする)
- agent が代わりに受け取る
- blob に書き込む
のいずれかをしなければならない.
どのように受け取ったことを認知するか?
-> やっぱり approve, transferFrom 形式の方が良くない?
状態の同期が取れてないのに tx を実行してしまう可能性がある.
-> CA storage の内容は L1 で常に検証されなければならない. 特定の人が管理している訳ではないので L2 が停止した時に取り出せなくなってしまう. 記録されていれば, L2 を再起動することもできる.
-> 要は, approve, transferFrom 形式だと allowance は CA storage におかなければならず, calldata 使用量が増える.
-> 増加差分は公開しておくので, オンラインに復帰したら早めにマージしてね.
## Reference
[1] https://eips.ethereum.org/EIPS/eip-2494
[2] https://ed25519.cr.yp.to/ed25519-20110926.pdf
###### tags: ``