Canton Network のプライバシー実現方法の検証
Canton Network とは、大手既存金融機関向けに設計されたブロックチェーンです。RWA トークン化をはじめとした既存金融が提供する金融商品の実装に採用されています。Canton Network 上のアプリで実際に運用されているものの中で最も規模が大きいものは Broadridge のレポ取引プラットフォーム DLR(Distributed Ledger Repo)で、公表されている処理額は 2026 年 5 月時点で月間 7 兆ドル規模、日次平均で 3,600 億ドル規模です。
こういった既存金融のオンチェーン化に Canton Network が採用されている理由の 1 つが、金融市場に求められるプライバシー要件をプロトコル自体がネイティブにサポートしていることです。取引の相手方や金額を競合に見せられない、という金融の必須要件を、アプリの実装ではなく台帳の仕組みで満たします。
この記事では、そのプライバシーが技術的にどう実現されているのかを、ローカルに立てたネットワークで検証します。
1. Canton Network の特徴
まずは Canton Network の全体像について簡単にご紹介します。Canton Network は Digital Asset が主導して 2023 年 5 月に立ち上がった L1 ブロックチェーンです。MainNet は 2024 年 6 月から動いています。スマートコントラクトは Daml と呼ばれる Haskell ベースの独自言語で記述します。ネイティブトークンは Canton Coin で、取引手数料と運営者への報酬に充てられます。
前述の通り Canton Network に代表される技術的特徴はプライバシー保護です。プライバシーを特徴とするブロックチェーンは他にもありますが、従来のプライバシーチェーンの全ノードに暗号文を送った上で検証のみ可能とするアプローチとは異なり、Canton Network ではそもそも必要な相手にしかデータを配らないというアプローチを取ります。Daml のコントラクトに書いた宣言から、プロトコルが情報の公開先を機械的に導き、アプリ側の実装をミスして漏らす、という経路を物理的に発生させないようにしています。
この性質が、1 つの取引に複数の当事者がいて、それぞれに見せたい範囲が違うという金融世界での取引に必要な要件に適しています。3 章のデモにて実際の金融取引を模したシナリオを Canton Network で実装します。
2. プライバシーをどう実現しているか
2.1 アーキテクチャ
Canton のネットワークは 2 種類のノードで構成されます。取引の当事者を預かり、Daml のロジックを実行し、データを保存する participant(バリデータとも呼ばれます)。そして participant 同士の通信を整理する synchronizer です。図1 がその全体像で、下段に participant が 3 台、上段に synchronizer があります。
図1: participant と party、そして台帳がどこにあるか(原寸で開く)
participant の配下には party がいます。party は台帳上の行為主体で、コントラクトの当事者になる識別子です。他のチェーンのアドレスに近いものですが、公開鍵・秘密鍵を持ちそれ自身でトランザクションに署名するアドレスと異なり、鍵とデータを預かって Daml を実行する participant に所属して、初めて取引に参加できます。1 つの participant が複数の party を預かることもでき、図1 では participant1 が bank と alice の 2 つを預かっています。
また、重要な点として participant は台帳全体を持ちません。自分がホストする party が当事者になっているコントラクトだけを保存します。図1 の participant3 が何も持っていないのは、charlie が当事者の取引が図の例ではまだないからです。
上段の synchronizer は、2 つの要素から成り立ちます。メッセージに順番を付けて宛先に配る sequencer と、当事者からの承認を数えて確定させるかどうかを決める mediator です。どちらも取引の中身を復号できません。扱うのは暗号化されたメッセージと、その宛先だけです。
なお party の識別子は alice::1220f0b2… の形をしていて、:: の後ろは participant の鍵から決まります。同じ participant が作った party は、この部分を共有します。後で出てくるデモでは bank と alice が同じ participant にいるので、識別子の後半が一致します。
2.2 Daml によるポリシー宣言
誰にデータが届くかは、Daml で書いたコントラクトの宣言から決まります。まず Daml のコントラクトがどんな形をしているかを、デモで扱う Iou テンプレートを例に見ます。
Iou は “I owe you” の略で、借用証書のことです。発行体(issuer)が保有者(owner)に対して金額(amount)を支払う義務を表します。銀行が発行する預金証書のようなものと考えれば十分で、Daml のチュートリアルでも定番の例です。デモでは bank が発行し、alice が受け取り、bob や charlie へ移転します。
template Iou
with
issuer : Party
owner : Party
amount : Decimal
where
signatory issuer
observer owner
choice Transfer : ContractId Iou
with
newOwner : Party
controller owner
do create this with owner = newOwner
Daml では、コントラクトの雛形を template として定義します。雛形にデータを埋めて台帳に載せたものが、個々のコントラクトです。template Iou の下は 2 つのブロックに分かれています。
with は、このコントラクトが持つデータです。ここでは発行体・保有者・金額の 3 つで、Party は 2.1 で見た party を指す型です。where には、このコントラクトに関わる当事者と、コントラクトに対して行える操作を書きます。
where の中の choice が、コントラクトに対して行える操作です。Transfer は保有者を差し替える操作で、内側にまた 3 つの要素があります。with は操作の引数で、ここでは移転先の newOwner。controller はこの操作を実行できる party で、ここでは現在の保有者 owner。do が実行内容で、create this with owner = newOwner は「同じ内容で owner だけを差し替えた新しい Iou コントラクトを作る」という意味です。
なお Daml のコントラクトは書き換えられません。この Transfer を実行すると元のコントラクトは消費(archive)され、do の中で作った新しいコントラクトに置き換わります。Transfer を実行すると owner = alice の Iou が消え、owner = bob の Iou が生まれる、という動きになります。
ここまでが構文です。プライバシーに直接効くのは、where の中で当事者の役割を宣言する 3 つのキーワードです。
| キーワード | 意味 |
|---|---|
signatory |
この契約の成立に同意が必要な当事者。契約とその全操作を必ず見る |
observer |
見えるが、単独では何もできない当事者 |
controller |
特定の choice を実行できる当事者 |
この宣言から、操作ごとの通知先が機械的に決まります。通知を受ける当事者を、公式ドキュメントでは informee と呼びます。コントラクトを作るときは signatory と observer の全員、コントラクトを消費する choice ではそこに実行者が加わります。読むだけの操作なら signatory と実行者だけで、observer には通知が行きません。状態が変わらないので知らせる必要がない、という理屈です。
Iou では、signatory が発行体の issuer だけで、保有者の owner は observer です。これは公式チュートリアルの SimpleIou と同じ形で、デモの木を小さく保つために選びました。owner も signatory に加えると、Transfer の中で新しい保有者の権限が必要になり、保有者が 1 回の操作で移転できなくなります。公式チュートリアルはこの場合に propose-accept(移転の提案コントラクトを作り、新しい保有者が受諾する 2 段階)を使うよう案内しており、公式の入門サンプルアプリ(Daml IOU Quickstart)の Iou も、signatory issuer, owner にこの 2 段階を組み合わせた形です。
本デモ簡略化の課題
signatoryはコントラクトを作る権限と消す権限を持つので、issuerだけをsignatoryにすると、発行体が保有者の同意なしにIouを archive できます。公式チュートリアルもこれをSimpleIouの「1 つの大きな問題」として挙げており、実運用では保有者もsignatoryに加えるのが筋です。この記事で確かめたいのは通知先の決まり方で、それはsignatory/observerの宣言から同じ規則で導かれるため、木を小さくして出力を読みやすくするほうを優先しました。
そのうえで、発行体は全 Iou の signatory なのですべての移転を見ます。これは宣言の意味そのものです。「signatory に指定した相手は必ず全部を見る」を、デモでも実際に確認します。
2.3 view への分割と暗号化
トランザクションは、操作を親子関係でつないだ木の形をしています。ある choice の do の中で別の choice を呼ぶと、呼ばれた側が子ノードになります。この木を、通知先が同じ部分ごとに切り分けたものが view です。
具体例で見ます。3 章のデモで実行する連鎖移転で、alice が持つ Iou を bob に移し、bob が受け取ったその Iou を続けて charlie に移す、という 2 段の Transfer を 1 つのトランザクションにまとめたものです。alice が提出すると、次の形の木ができます。
- 根(node 0): 連鎖を実行する
choice。3.3 で作る合意コントラクトChainTransferAgreementのExecuteChainを、alice が実行する - その子(node 1): alice の
Iouに対するTransfer。さらにその子(node 2)としてowner = bobの新しいIouが作られる - もう 1 つの子(node 3): node 2 で作られた
Iouに対するTransfer。その子(node 4)としてowner = charlieのIouが作られる
ここに 2.2 の規則を当てます。1 段目の Transfer(node 1, 2)は、signatory の bank、実行者の alice、新しい owner の bob に通知されます。2 段目(node 3, 4)は bank、実行者の bob、新しい owner の charlie に通知されます。charlie が直接関わるのは 2 段目だけですが、alice には 2 段目も含めた全イベントが見えます。通知先が変わる境目で木を切ると、view が 2 つできます。
view ごとに別の鍵で暗号化し、それぞれを封筒(envelope)に入れて sequencer に渡します。sequencer は復号鍵を持たないので、扱えるのは封筒と宛先だけです。関係のないノードには何も届かないため、そのノードは取引が起きたことすら知りません。
図2: 1 つのトランザクションが view に分かれ、当事者ごとに違う範囲が届く(原寸で開く)
図2 は上の木を左上に、それが view に分かれて暗号化される様子を右上に、sequencer を経て各 participant に届く範囲を下段に描いています。バイト数などの数値は、この後のデモで実際に観測したものです。
3. プライバシーが守られていることのデモ
3.1 シナリオ: ブローカー経由の売買
題材は仲介取引にします。Alice が持っている資産を、ブローカーの Bob を経由して Charlie に売る。このとき Bob の商売は、2 つの条件で成り立っています。
1 つは、Charlie に Alice の関与を見せないことです。相対の金融取引には事前の与信関係や市場へのアクセス権が要り、両端が自力で相手を見つけて契約するのは難しいので、双方と関係を持つ Bob が間に立ちます。もう 1 つは、決済が同時に起きることです。Bob が自己資金を持たずに転売を成立させるには、Alice → Bob と Bob → Charlie が同時に確定しなければなりません。片方だけ成立すると、Bob が決済リスクを負います。
普通のブロックチェーンでは、この 2 つが両立しません。1 つのトランザクションにまとめれば全参加者に全部が見えます。見せないために 2 つに分割すれば、今度はアトミック性が壊れます。
Canton での解決策は「1 つのトランザクションのまま、見える範囲を内側で切る」で、仕組みは 2.3 で見たとおりです。これが実際に動くのかを、3 台の participant を持つローカルネットワークで 3 つの検証に分けて確かめます。検証①では、無関係な participant にデータが届かないこと。検証②では、1 つのトランザクションの内側で見える範囲が切れること。検証③では、順序を決める側にも中身が見えないことを確認します。
3.2 環境
デモ環境は、Canton のネットワーク本体、その上で動く Daml のアプリ、外からトランザクションを投げるクライアント、結果を覗く観測ツールの 4 層で組んでいます。起動手順とコマンドはリポジトリの README にまとめてあるので、ここでは構成の考え方だけを説明します。
図3: デモ環境の構成(原寸で開く)
ネットワーク本体は、2.1 の構成をそのまま最小で再現したものです。synchronizer として sequencer 1 台と mediator 1 台、participant を 3 台。合計 5 ノードを 1 つの JVM プロセス(canton daemon)に同居させています。ストレージはすべてメモリにしており、プロセスを落とすと台帳も party も消えますが、デモ用途なので問題ありません。sequencer も外部依存のない reference 実装を使っています。
participant を 3 台に分けているのが、この構成で一番大事な判断です。確かめたいのは「関係のないノードにはデータが届かない」という主張なので、party が別々のノードにいなければ検証になりません。1 台の participant に 3 つの party を置いても Ledger API のフィルタで見え方は変わりますが、それはデータが同じ DB にある状態で API が隠しているだけです。そこで participant1 に bank と alice、participant2 に bob、participant3 に charlie を置き、検証①では participant3 を「取引に無関係なノード」として使います。bank を alice と同居させているのは、ノードを増やさずに「signatory は全部を見る」を同時に確かめるためです。
起動直後に走る bootstrap スクリプトが、synchronizer を初期化し、3 台の participant をそこに接続し、後述の dar を全 participant に投入し、party を作ります。party の識別子は participant の鍵から決まるので、起動ごとに変わります。そのため bootstrap は最後に、party 識別子と「どの party がどの participant にいるか」の対応表をファイルに書き出し、以降の層はそれを読んで動きます。
アプリは 2.2 と 3.3 で説明する Daml の template で、コンパイルして dar にしたものを全 participant に投入します。Canton では、取引を検証する participant がそのコードを持っていなければ承認できないので、無関係なはずの participant3 にも dar は入ります。コードは全員が持ち、データは当事者だけが持つ、という分離です。
クライアントは Daml Script です。検証①②のトランザクションを組み立てて submit する役で、bootstrap が書き出した対応表を渡すと、alice の submit は participant1 へ、bob の submit は participant2 へと、party ごとに正しいノードの Ledger API に振り分けます。実運用で各組織が自分のノードからコマンドを出す状況を、1 つのスクリプトで模しています。
観測ツールは Canton console です。3 台の participant の管理 API と Ledger API に外から同時に接続し、同じ問いを 3 台に投げて答えを並べます。使うのは 2 つの API で、participant が保存している active contract を返す state.acs と、トランザクションを木の形で返す updates.transactions です。検証③では、これに加えて sequencer のログを DEBUG レベルで読みます。
3.3 誰が実行できるかが、プライバシーに縛られる
検証②で使う連鎖移転の template を先に見ておきます。ここに、Canton のプライバシーが開発者に課す制約が現れます。
業務の感覚では、実行するのはブローカーの Bob です。Alice は「売りたい」と伝えるだけで、買い手を見つけて決済を執行するのは仲介業者の仕事です。
ところが Bob 主導にはできません。Alice が持つ Iou の当事者は bank と alice だけで、bob は入っていません。だから participant2 はそのコントラクトを持っておらず、トランザクションの入力として使えないのです。見えないものは、使えません。
そこで Alice と Bob の合意コントラクトを先に作り、Alice が実行する形にします。
template ChainTransferAgreement
with
sender : Party
middle : Party
where
signatory sender, middle
nonconsuming choice ExecuteChain : ContractId Iou
with
iouCid : ContractId Iou
finalOwner : Party
controller sender
do
midIou <- exercise iouCid Transfer with newOwner = middle
exercise midIou Transfer with newOwner = finalOwner
2 段目の移転には Bob の権限が必要ですが、このコントラクトの signatory に middle(Bob)が入っているため、choice の実行中は Bob の権限が使えます。2 段目の対象は同じトランザクション内で作られたコントラクトなので、解決の問題も起きません。
Daml Script 側は、これを 1 回の submit で呼びます。
step2 : Parties -> Script ()
step2 p = do
iou <- submit p.bank do
createCmd Iou with issuer = p.bank, owner = p.alice, amount = 50.0
prop <- submit p.alice do
createCmd ChainTransferProposal with sender = p.alice, middle = p.bob
agr <- submit p.bob do
exerciseCmd prop AcceptChain
_ <- submit p.alice do
exerciseCmd agr ExecuteChain with iouCid = iou, finalOwner = p.charlie
pure ()
最後の submit が、この記事で見たい 1 トランザクションです。
3.4 検証①: 当事者でない participant には何も入らない
まず単純な移転から確かめます。bank が alice に Iou を発行し、alice がそれを bob へ移します。charlie は当事者ではありません。
dpm script --participant-config participants.json \
--dar test/.daml/dist/privacy-demo-test-0.0.1.dar \
--script-name PrivacyDemo:step1 \
--input-file parties.json \
--upload-dar true
検証は Canton console から行います。3 つの participant に同じ問いを投げるだけです。
participants.all.foreach { p =>
val acs = p.ledger_api.state.acs.of_all()
println(s"[${p.name}] ${acs.size} contracts")
...
}
acs.of_all() は、その participant が保存している active contract をすべて返します。party でフィルタした結果ではなく、ノードが持っているものそのものです。
=== 各 participant が保存している active contract ===
[participant1] 1 contracts
Iou(issuer=bank, owner=bob, amount=100.0000000000)
[participant2] 1 contracts
Iou(issuer=bank, owner=bob, amount=100.0000000000)
[participant3] 0 contracts
participant3 は 0 件です。participant1 が持っているのは bank が signatory だからで、participant2 が持っているのは bob が owner(= observer)だからです。2.2 の宣言がそのまま出ています。
ここまでは、Corda でも Fabric のチャネルでも言えることです。固有の性質が出てくるのは次からです。
3.5 検証②: 同じ updateId で、5 events と 1 event に分かれる
ExecuteChain を実行し、同じトランザクションを 3 つの participant から読みます。TransactionShape に LEDGER_EFFECTS を指定すると、exercise ノードを含む木の形で取得できます。
val txs = p.ledger_api.updates.transactions(
partyIds = Set(pty),
completeAfter = PositiveInt.tryCreate(100),
endOffsetInclusive = Some(p.ledger_api.state.end()),
transactionShape = TransactionShape.TRANSACTION_SHAPE_LEDGER_EFFECTS,
)
結果です。
[participant1 / alice]
updateId = 122037b8df59f2fd95325b232de21a5a89e52f5c1b929f660b0dedd4477a6d8244bd
commandId = 87e139b7-fb3b-495d-9958-2a0a84d4b0f7
events = 5
node=0 exercise ChainTransferAgreement.ExecuteChain witnesses=[alice]
node=1 exercise Iou.Transfer witnesses=[alice]
node=2 create Iou(owner=bob, amount=50.0000000000) witnesses=[alice]
node=3 exercise Iou.Transfer witnesses=[alice]
node=4 create Iou(owner=charlie, amount=50.0000000000) witnesses=[alice]
[participant2 / bob]
updateId = 122037b8df59f2fd95325b232de21a5a89e52f5c1b929f660b0dedd4477a6d8244bd
commandId = (空)
events = 5
node=0 exercise ChainTransferAgreement.ExecuteChain witnesses=[bob]
node=1 exercise Iou.Transfer witnesses=[bob]
node=2 create Iou(owner=bob, amount=50.0000000000) witnesses=[bob]
node=3 exercise Iou.Transfer witnesses=[bob]
node=4 create Iou(owner=charlie, amount=50.0000000000) witnesses=[bob]
[participant3 / charlie]
updateId = 122037b8df59f2fd95325b232de21a5a89e52f5c1b929f660b0dedd4477a6d8244bd
commandId = (空)
events = 1
node=0 create Iou(owner=charlie, amount=50.0000000000) witnesses=[charlie]
updateId は 3 者で一致しています。同じ 1 つのトランザクションです。それでも charlie に見えるのは 1 イベントだけで、Iou が自分のものになった create だけが届いています。
charlie が知らないことを並べると、範囲の狭さがはっきりします。alice が関与したことを知りません。ExecuteChain という choice が実行されたことも、ChainTransferAgreement というコントラクトの存在も知りません。bob が誰かから受け取った直後に自分へ渡したという経緯も見えません。charlie の側から見えるのは「bank が発行した Iou 50.0 の所有者が自分になった」という事実だけです。
commandId が alice にだけ入っている点も、同じ原則の現れです。どのコマンドから生まれたトランザクションかは、提出した本人だけが知ります。
node 番号も見比べておきます。alice の側では最後の create が node=4 ですが、charlie の側では node=0 です。contract の識別子は同じものを指しています。charlie は、自分の create が元の木で何番目のノードだったかも分かりません。
3.6 検証③: sequencer に見えるのは暗号文と宛先だけ
順序を決める側から何が見えるかを確認します。ログレベルを DEBUG まで上げて読みます。
sequencer が記録するのは、リクエストの外形だけです。これは INFO レベルでも出ます。
'PAR::participant1::12205f6288dd...' sends request with id '46b3cb98-...'
of size 5794 bytes with 4 envelopes.
Request to send submission with id 46b3cb98-... with max sequencing time
2026-08-25T08:22:04.228500Z from PAR::participant1::12205f6288dd... to
Set(MediatorGroupRecipient(group = 0),
MemberRecipient(PAR::participant1::12205f6288dd...),
MemberRecipient(PAR::participant3::1220029fc38a...),
MemberRecipient(PAR::participant2::12207f694d69...)).
送信元、リクエスト ID、サイズ、封筒の数、そして宛先の一覧。sequencer が扱うのはここまでです。
封筒の中身がどういう型をしているかは、配られた側のログから読めます。次は participant1 が受け取った Deliver で、宛先が participant1 の封筒だけが入っています。
Deliver(
timestamp = 2026-08-25T08:21:04.250183Z,
message id = Some(46b3cb98-70db-4c3a-a4f5-3510a6f3462f),
Batch(
Seq(
OpenEnvelope(
RootHashMessage(root hash = SHA-256:37b8df59f2fd..., payload size = 0),
recipients = Recipients(RecipientsTree(
recipient group = Seq(MediatorGroupRecipient(group = 0),
MemberRecipient(PAR::participant1::12205f6288dd...))))
),
OpenEnvelope(
EncryptedMultipleViewsMessage(
view hashes = ViewHash(SHA-256:7286888092ad...),
view type = TransactionViewType,
size = 1648,
number of view keys = 2,
view encryption scheme = AES128-GCM
),
recipients = Recipients(RecipientsTree(
recipient group = Seq(MemberRecipient(PAR::participant1::12205f6288dd...),
MemberRecipient(PAR::participant2::12207f694d69...))))
),
OpenEnvelope(
EncryptedMultipleViewsMessage(
view hashes = ViewHash(SHA-256:3dbe3bb1adc3...),
view type = TransactionViewType,
size = 1067,
number of view keys = 2,
view encryption scheme = AES128-GCM
),
recipients = Recipients(
RecipientsTree(
recipient group = Seq(MemberRecipient(PAR::participant1::12205f6288dd...),
MemberRecipient(PAR::participant2::12207f694d69...)),
children = RecipientsTree(recipient group = Seq(
MemberRecipient(PAR::participant1::12205f6288dd...),
MemberRecipient(PAR::participant3::1220029fc38a...)))
)
)
)
)
)
)
金額も party 名もテンプレート名も出てきません。あるのはハッシュとサイズと暗号方式です。今回確認した DEBUG ログにも、取引の中身は出ていません。
この出力からは、2.3 で説明した構造も読み取れます。EncryptedMultipleViewsMessage が 2 つあり、これが view の 2 つに対応します。それぞれ AES128-GCM で暗号化され、number of view keys = 2 は受け取り手ごとに鍵が包まれていることを示します。
3 番目の封筒の宛先が入れ子になっている点が、検証②の結果と直接つながります。親の宛先は participant1 と participant2 で、その子の宛先に participant3 が入っています。charlie に届くのは子の部分だけです。だから charlie の側では 1 イベントしか見えません。
RootHashMessage の宛先には mediator が入っていますが、payload size = 0 です。mediator が受け取るのは全 view をまとめたハッシュと、誰の承認が必要かという情報だけです。承認を数えて確定を決める側も、確定させた取引の中身を知りません。
4. まとめ
この記事の目的は、Canton Network が提供するプライバシーが技術的にどう実現されているかを検証することでした。Canton のプライバシーは「見せない相手にデータを送らない」ことで成り立っており、誰に送るかは Daml の signatory、observer、controller という宣言からプロトコルが導いている、この 2 点が、ローカルの 3 台の participant で実機の出力として確認できました。
今回の検証で確かめたのは、仲介取引に必要な 2 つの条件が 1 つのトランザクションの中で両立することです。買い手には元の売り手の関与が見えず、無関係なノードには取引が起きたことすら届かず、順序を決める sequencer と確定を判定する mediator も中身を復号できません。それでいて 2 段の移転は同時に確定します。「取引相手と金額を競合に見せない」という金融の必須要件を、アプリの実装に頼らず台帳の仕組みで満たしていると言えます。Broadridge DLR のように競合する金融機関が同じ台帳に乗る場面で採用が進んでいる理由も、ここにあると考えています。
もちろん、既存の金融商品を Canton Network 上に載せるには、プライバシー以外の面でもハードルがあるはずです。Haskell ベースの Daml で業務ロジックを書ける人材は多くありません。各機関が自前で participant を運用する前提なので、鍵管理やノード運用の責任も自分たちで持つことになります。既存の勘定系や決済システムとの接続、法制度上の位置づけの整理も、チェーンの仕組みだけでは解決しません。この記事ではこれらには踏み込めていません。それでも、Broadridge DLR の月間 7 兆ドル規模の処理や、Euroclear・LSEG のクロスボーダーレポ、MUFG の国債レポの実証など、既存金融がすでに本番や実証で使い始めている事実があります。競合と台帳を共有しながら見せる範囲を契約ごとに制御できる仕組みは、その採用を支える土台です。既存金融のオンチェーン化の受け皿として、Canton Network が有力な候補であることは変わらないと考えています。
参考
- Canton Network Documentation
- Privacy Model Explained — Canton Network Docs
- Parties and Authority — Daml SDK Docs —
SimpleIouの問題点と propose-accept パターン - Daml IOU Quickstart Tutorial —
signatory issuer, ownerのIouとIouTransfer - canton-privacy-demo — この記事で使ったコード
採用状況について。
- Who Is Building on the Canton Network in 2026? — Interstice Digital — Broadridge DLR、GS DAP、HSBC Orion などの整理
- Canton advances cross-border repo to free up $300 trillion assets via tokenization — CoinDesk — Euroclear / Euronext / LSEG のクロスボーダーレポ
- MUFG が挑む「国債レポのオンチェーン化」とは? — 日本国債レポの実証