部分署名

部分署名を使うと、複数の関係者が同じトランザクションに、異なるタイミングや異なるデバイスで署名できます。コーディネーターがメッセージを構築し、必要な各署名者がシリアライズされたメッセージのバイト列そのものに署名します。コーディネーターは送信前に署名を検証して統合します。

署名が承認するのはバイト列であり、意図ではありません

手数料支払者、ブロックハッシュ、instructionの順序、アカウントリスト、あるいはinstruction dataのいずれかを変更すると、別のメッセージが生成され、それまでに集めたすべての署名が無効になります。

部分署名のフロー

  1. トランザクションのinstructionsと、誰が手数料を支払うかについて合意します。
  2. トランザクションの有効期間と手数料支払者を設定します。
  3. メッセージを1回だけシリアライズします。そのバイト列は変更不可として扱います。
  4. メッセージのバイト列と人が読める形式の概要を、各署名者に配布します。
  5. 各Ed25519署名を収集し、同じメッセージのバイト列に対して検証します。
  6. 署名を、対応する必須署名者のアドレスに紐付けます。
  7. 必要な署名がすべて揃っていて有効であることを確認してから、送信します。

完全な例

以下の例では、手数料支払者とSOLの送信者がそれぞれ独立して署名します。コーディネーターは両方の署名を検証して統合し、完成したトランザクションを送信します。

この例では、コーディネーターと各署名者の境界を明確にするために、生のEd25519署名を使用しています。まったく同じメッセージのバイト列に署名する限り、ウォレット、ハードウェアデバイス、カストディサービス、オフライン署名者のいずれも、ローカルのkeypairの代わりに使用できます。

署名前にメッセージを固定する

すべての署名は、シリアライズされたトランザクションメッセージを対象とします。メッセージには次のすべてが含まれます。

  • 手数料支払者
  • 最近のブロックハッシュまたはdurable nonce
  • すべてのプログラムとアカウントのアドレス
  • アカウントの署名者権限と書き込み可能権限
  • instructionの順序とinstruction data

まずこれらのフィールドを構築し、メッセージを1回だけシリアライズして、そのバイト配列をすべての署名者に配布します。各署名リクエストと併せてメッセージのダイジェストを保存しておくと便利です。これにより、コーディネーターは別のメッセージに対して返された署名を拒否できます。

メッセージをデシリアライズして変更し、それまでに集めた署名が有効なままであることを期待してはいけません。期限切れのブロックハッシュの差し替えや手数料支払者の変更のように、運用上の変更に見えるものであっても、すべての署名者が再度署名する必要があります。

手数料支払者の調整

手数料支払者は常に必須の署名者であり、メッセージを固定する前に決めておく必要があります。そのアカウントに、基本手数料と優先手数料を支払えるだけのSOLがあることを確認してください。スポンサーやバックエンドが手数料を支払う場合は、ユーザーの署名を集める前に、そのアドレスをメッセージに含めてください。スポンサーを後から追加すると、署名対象のバイト列が変わってしまいます。

コーディネーターは、受け取った署名が必須署名者として列挙されたアドレスのものであることを検証する必要があります。任意の公開鍵を受け入れて、トランザクションに追加してはいけません。

トランザクションの有効期間の管理

最近のブロックハッシュを使うトランザクションは、そのブロックハッシュがvalidatorの最近のブロックハッシュキューに残っている間だけ有効です。複数の関係者による署名フローを開始する前に、すべての署名者が lastValidBlockHeight までに応答できるかどうかを見積もってください。

ブロックハッシュが期限切れになった場合は、新しいブロックハッシュで新しいメッセージを構築し、すべての署名を改めて集めます。より時間がかかる可能性があるワークフローや、オフライン署名者を含むワークフローでは、durable nonceを使用してください。durable nonceは最近のブロックハッシュの有効期間の制約を回避できますが、そのnonceを進めたり、その他の方法で消費したりすると、保留中のトランザクションは無効になります。

送信前の検証

返されたすべての署名について、次の手順を実行します。

  1. 固定したメッセージのバイト列と、想定される署名者の公開鍵に対して、署名を検証します。
  2. トランザクションの署名配列内で、その署名者に対応する位置に署名を追加します。
  3. 組み立てたトランザクションに、必須署名者全員分の有効な署名があることを確認します。
  4. メッセージを再構築せずに、シリアライズしたトランザクションを送信します。

送信後は、署名済みメッセージに含まれていたものと同じ有効期間の情報を使って確認します。確認の結果、ブロックハッシュの期限切れまたはnonceの消費が報告された場合は、変更したトランザクションで再試行せず、署名フローを最初からやり直してください。

Is this page helpful?

目次

ページを編集
© 2026 Solana Foundation. 無断転載を禁じます。