Skip to main content

原文準拠 Phase 3:DApp開発

1.2 Compact の基礎

Midnight Academy Phase 3 / Unit 1 / 1.2 の原文準拠版。Compact プログラムの構造(pragma・import・ledger・circuit・disclose・型・constructor・assert)を、本物のコードで正確に。


📘 Academy原文準拠 | Phase 3 · Unit 1 · Lesson 1.2 Compact Language Fundamentals 内容に忠実な日本語版です。原文(英語)・動画は公式 Academy(外部リンク・別タブで開きます)、文法の正本はCompact リファレンス(外部リンク・別タブで開きます)を。

JavaScript / TypeScript など C 系の言語を書いたことがあれば、Compact は一見なじみがあります(セミコロン、波かっこ、if 文…)。でも Compact は汎用言語ではありませんMidnight 上で動くゼロ知識回路を定義するという、ただ1つの目的のために作られています。

その制約が言語のすべてを形づくります。TypeScript で当たり前のものが無かったり、逆に disclose のような一見へんなものが「プライバシーの核心」だったりします。

動画で学ぶ(公式)

🎬 Compact 言語の基礎(概要) YouTubeで開く ↗
🎬 補足の公式解説動画 YouTubeで開く ↗

Compact プログラムの骨格

どの Compact も同じ基本構造です。次のレッスンでデプロイする hello-world 契約を見てみましょう。

これで完全な・デプロイ可能な契約です。実質6行。順に分解します。

pragma(バージョン宣言)

どのバージョンの Compact 向けかをコンパイラに伝えます。省略可ですが必ず書くべき。Compact は進化中で、マイナー更新に破壊的変更が入ることがあるためです。

  • 範囲指定OK:>= 0.20 && <= 0.22>= 0.20 単独なら「0.20 以上」。
  • パッチ番号(0.20.0 など)は書かない。マイナー番号まで。

import(標準ライブラリ)

Counter / Map / Set などの型や、persistentHash などの組み込み回路が使えるようになります。 ※ disclose言語そのものの一部で、import 不要・常に使えます。

ledger 宣言(公開状態)

ここが Solidity 等と大きく違うところ。契約の本体(contract body)が無く、ledger 宣言はトップレベルに書きます。

  • ledger 宣言は、Midnight の公開台帳に永続保存されるデータ。
  • export を付けると、DApp のフロント(TS SDK)から読めるようになる。付けないと、チェーン上には在るが外から読めない。
  • sealed を付けると、constructor で一度だけ設定でき、その後は変更不可

データ型

ZK 回路で効率よく証明できることを軸に設計された、絞り込まれた型システムです。普通の意味での文字列・配列・オブジェクトはありません。

プリミティブ型

プリミティブ型の一覧表。Field(有限体の要素・ZK回路の基本数値型)、Boolean(真または偽)、Bytes(固定長バイト配列・Nバイト)、Uint(Nビットの符号なし整数)、範囲制限つき Uint(0からMAXまで)を、型・概要・例の3列で示す表

説明
Field 最も基本。ZK計算はすべて field 要素の上で行う。ハッシュ・コミットメント・一般計算に
Uint<N> / Uint<0..MAX> 同じ型族。Uint<64>Uint<0..(2^64-1)> と同等。範囲を明示したいとき下限上限の形
Bytes<n> n バイトの固定長データ
Boolean 真偽
Opaque<"string"> 文字列の扱い方。回路内では中身を見ず、ハッシュとして扱う。TS フロントでは普通の文字列として読める。バイナリは Opaque<"Uint8Array">

コレクション型

コレクション型の一覧表。Counter(増減できるカウンター)、Map(キーと値の対応付け)、Set(重複しない値の集合)、Vector(固定長配列)、Maybe(値があるかないかのオプション値)を、型・概要・例の3列で示す表

  • Counter特別。直接代入せず、.increment(n) / .decrement(n) / .read() で操作。並行トランザクションを正しく扱うため。
  • Map / Set … 期待どおり。しかも .lookup() / .member() / .isEmpty() / .size() などの問い合わせは回路内でも動く

カスタム型(enum / struct)

circuit(オンチェーンの関数)

circuit は、ZK回路にコンパイルされる関数です。誰かが呼ぶと、prover が「計算は正しく行われた」という ZK 証明を作り、ネットワークがそれを検証します。

  • 戻り型 [](空タプル)=値を返さない。Compact に Void は無く、[] が Void の代わり(古い例で Void を見たら [] に読み替え)。
  • 値も返せます:
  • 修飾子:

disclose キーワード(最重要)

Compact は「プライバシーがデフォルト」という厳格なルールを持ちます。

  • 回路パラメータや witness から来た値は、コンパイラが秘密とみなす
  • その値を公開台帳に書くなら、disclose() で囲んで「これは意図的に公開してよい」と明示する必要があります。

囲まないと、コンパイラが “implicit disclosure” エラーで止めます(うっかり漏洩の防止)。

さらに、witness 由来の値で分岐するときも disclose が要ります。

ルールは単純:秘密の値が「公開のなにか(台帳書き込み/公開状態に影響する分岐)」に影響するなら、disclose が必要

型キャスト

Compact はキャストに厳格です。許されたキャストだけが可能で、static / conversion / 実行時チェックに分類されます。 FieldBytes<n>Uint<0..m>Uint<0..n> などはキャスト表で定義された範囲でのみ可能。表に無いキャストは不可(→ 公式 lang-ref の cast 表(外部リンク・別タブで開きます))。

constructor(初期化)

省略可。デプロイ時に一度だけ実行され、初期値(特に sealed フィールド)を設定します。

デプロイ後は二度と呼べず、sealed は変更不可。

assert(条件チェック)

失敗すると回路全体が失敗し、取引は拒否されます。エラーメッセージは開発者向けで、オンチェーンには現れません

組み込み関数の注意

組み込み関数の一覧表。disclose(非公開の値を公開してよいと明示的に開示)、persistentHash(SHA-256ベースの永続ハッシュ)、persistentCommit(値に対する秘密コミットメントを作成)、pad(文字列を固定長のバイト列にパディング)、assert(条件が偽なら回路を失敗させる)、default(型のデフォルト値を返す・数値は0、コレクションは空)を、関数・役割の2列で示す表

標準ライブラリは persistentHash などを提供します。ただし:

⚠️ public_key() は組み込み関数ではありません(そう見える例があるが誤り)。公開鍵の導出は persistentHash パターンで行います。

pad(32, "myapp:pk:") のようなラベル(ドメイン分離)を混ぜるのがポイントです(用途ごとにハッシュを分ける)。

開発者として押さえる点

  • 骨格:pragma → import → ledger(トップレベル)→ circuit。契約本体ブロックは無い
  • 公開は ledger、秘密は witness、境目に disclose。witness 由来の分岐にも disclose が要る(ここが落とし穴)
  • [] は Void の代わり。pure circuit は状態に触れないユーティリティ
  • 型は ZK 前提(Field / Uint<N> / Bytes<n> / Opaque<...>)。Counter.increment/.readMap/Set の問い合わせは回路内でも動く
  • キャストは表にあるものだけpublic_key()組み込みでないpersistentHash パターンで作る

やさしい版・公式へ

つぎに読むページ

➡️ 原文準拠コースの入口へ戻る。このコースについて(次のレッスンは順次追加します)