DES · 1 block
64ビットブロックを暗号化する
鍵とブロックを渡すと、チェーン上の des::encrypt_block が16段のFeistelを回して返します。
いま呼んだ Move の実装 — des.move(FIPS の表と16段の Feistel)
Feistel · 16 rounds
途中経過を全部見る
L/Rの16段ぶんと48ビットのラウンド鍵。どちらも des::encrypt_block_trace と des::round_keys の戻り値です。
| round | L | R | round key (48-bit) |
|---|
DES-CBC · PKCS#7
文章をまるごと暗号化して戻す
ブロック長に満たない分はPKCS#7で詰め、各ブロックを直前の暗号文とXORします(CBC)。
FeliCa · Authentication1 / 2
カードとリーダの相互認証を、チェーン上でやり直す
鍵階層の畳み込み、IDmによる個別化、2-key 3DESによるチャレンジ交換、封をした Authentication2レスポンスまで。FeliCaカードユーザーズマニュアル(非公式版) の §7.1・§7.3 をそのままMoveに書き下ろしたものです。
| 手順 | 向き | 値 |
|---|
R→C はリーダからカードへ、C→R はカードからリーダへ送られる値です。
いま呼んだ Move の実装 — felica_auth.move(§7.1・§7.3 の書き下ろし)
Groth16 · BN254
鍵を見せずに「鍵を知っている」を証明する
上の認証は鍵をそのままトランザクションに入れてしまいます。こちらはPoseidonコミットメントの原像を知っていることだけを証明します。
証明している主張そのもの zk/circuits/card_key.circom
チェーン側の検証コード — zk_verifier.move
検証鍵と証明のバイト列
On-chain record
実際に送ったトランザクション
読み取り専用クエリはガスも署名も要りませんが、こちらは本物のトランザクションです。ダイジェストからエクスプローラで追えます。
How it was built
このPOCの作り方
すべてClaude Codeのクラウド環境の中で完結しています(ローカル環境なし・ウォレット拡張なし)。
- Moveパッケージ:
des.move(FIPS 46-3のIP/FP・S-box・鍵スケジュールをそのまま実装)、felica_auth.move(非公式マニュアル §7.1・§7.3 の相互認証)、zk_verifier.move、gate.move。Moveのユニットテスト34件が通っています(FIPSの既知答、パリティビットが無視される性質、CBCとECBの差、FeliCa各値のPython参照実装との一致、リプレイ拒否、Groth16の受理/拒否)。 - ZK回路:
circomでPoseidonコミットメントの原像知識を回路化し、snarkjsでGroth16のセットアップと証明を生成。 - 直列化:snarkjsのJSONを arkworks の圧縮形式に変換(G1は32バイト、G2は64バイト、フラグはyの符号)。
sui::groth16が受け取れるのはこの形式だけです。 - 公開:Sui CLIのバイナリ配布が取得できない環境だったので、
sui-moveをソースからビルドしてコンパイルし、TypeScript SDKでパッケージを公開しました。 - 接続:公開フルノードのJSON-RPCは廃止済みのため、このページはgRPC (gRPC-web) で
simulateTransactionを呼んでいます。これが以前のdevInspectにあたる読み取り専用の経路です。