edgeX Stark曲線署名の実装とHMAC-SHA256との比較
はじめに
edgeX exchange のAPIを統合する際、最初に直面するのがStark曲線ECDSA署名という独特な認証方式です。一般的な仮想通貨取引所のHMAC-SHA256とは全く異なるアプローチを採用しています。
この記事では、edgeXのStark曲線署名の実装方法を解説します。
サンプルコード
実際に動作するサンプルコードはこちらです: Go implementation of edgeX Exchange API authentication using Stark curve ECDSA signatures.
アカウント登録や Discord の #support-ticket からAPIのホワイトリスト申請が必要です。
前提知識
edgeX Exchange とは?
edgeX exchange は、オーダーブック型のパーペチュアルDEXです。近年盛り上がる Perp DEX 市場(例:Hyperliquid など)の文脈で比較されるプロジェクトの一つです。
なぜ edgeX Exchange か?
*エアドロハンティングを推奨する意図はありません。
エアドロハンティングの一環として、edgeX のポイントプログラムに参加しています。
参加理由:
- Perp DEX セクター全体が活況で、edgeX もその一角として存在感が出てきている。
- Amber Group のインキュベーション案件として紹介されており、一定の注目度がある。
- ポイント配分は“取引高”が主軸で、要件が比較的シンプル(ただし紹介やTVLなど他要素も加点対象)。
- 運営の経歴については大手金融出身者がメンバーになっているなどの言及も見かけます。*一次情報での確認は未了
個人的な戦略:
少ない原資で取引高を増やす取引ボットを適切に運用することです。
運用実績としては、1,000ドル原資で、ほぼお削りなしで 1日 200,000ドル の取引高を詰めている状況です。つまり、メイカー手数料 0.012% なので、取引高から見れば 1日に edgeX exchange に 24 USD ほどの手数料を払っており、ある程度のリターンを期待している状況。
想定する読者
- edgeX Exchange APIを統合するエンジニア
- Stark曲線署名の実装を理解したい方
この記事で得られること
- edgeX Stark曲線署名の仕組みと実装方法の理解
- HMAC-SHA256との違いと設計判断の根拠
- 実装時の典型的なアンチパターンと回避策
実装方法の解説
1. REST API署名の実装
REST API署名は、Keccak-256ハッシュとStark曲線ECDSA署名を組み合わせて生成します:
処理ステップ:
- 秘密鍵のパース: 16進数文字列をbig.Intに変換
- Keccak-256ハッシュ: メッセージをハッシュ化(Ethereum互換)
- K_MODULUSでmod: ハッシュ値を群位数で剰余演算
- ECDSA署名生成: Stark曲線で署名(r, s)を計算
- 公開鍵Y座標の計算: 秘密鍵から公開鍵のY座標を導出
- 署名フォーマット: r||s||Y形式で結合(各64文字、計192文字)
重要な定数:
K_MODULUS = 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f
メッセージ形式: TIMESTAMP + METHOD + PATH + PARAMS(区切り文字なしで連結)
2. L2オーダー署名の実装
L2オーダー署名は、Pedersenハッシュを使用してStarkEx Layer 2との互換性を確保します:
処理ステップ:
- オーダーパラメータのパース: vault, amount, token, nonce, expirationTimeを数値化
- Pedersenハッシュ計算: 全パラメータをPedersen関数でハッシュ化
- FIELD_PRIMEでmod: ハッシュ値を体の素数で剰余演算
- ECDSA署名生成: Stark曲線で署名(r, s)を計算
- 署名フォーマット: r||s形式で結合(各64文字、計128文字)
重要な定数:
FIELD_PRIME = 0x0800000000000011000000000000000000000000000000000000000000000001
オーダーパラメータ:
- VaultSell/VaultBuy: vault ID
- AmountSell/AmountBuy: 取引高
- TokenSell/TokenBuy: トークンアドレス(16進数)
- Nonce: リプレイ攻撃防止用
- ExpirationTime: 有効期限(Unixタイムスタンプ)
REST署名とL2署名の違い:
- REST署名: Keccak-256 + K_MODULUS(群位数)
- L2署名: Pedersen Hash + FIELD_PRIME(体の素数)
3. REST + L2署名の統合
実際のリミットオーダー作成では、両方の署名が必要です:
処理フロー:
- L2オーダー署名を生成: オーダーパラメータ(vault, amount, tokenなど)からPedersenハッシュ→ECDSA署名
- REST API署名を生成: HTTPメソッド、パス、タイムスタンプ、ボディハッシュからKeccak-256ハッシュ→ECDSA署名
-
HTTPリクエストを送信:
- Header:
X-edgeX-Api-Signature: {restSig}(192文字) - Body:
{"l2_signature": "{l2Sig}", ...}(128文字)
- Header:
2段階署名が必要な理由:
- REST署名: API認証(サーバーが要求の正当性を検証)
- L2署名: オーダー検証(StarkEx L2が決済時に検証)
HMAC-SHA256との比較
技術比較
| 項目 | HMAC-SHA256 | Stark ECDSA(edgeX) |
|---|---|---|
| アルゴリズム | 対称鍵 | 非対称鍵 |
| 署名サイズ | 64文字 | 128-192文字 |
| 検証 | 秘密鍵が必要 | 公開鍵のみ |
| L2互換性 | なし | あり |
edgeXがStark ECDSAを採用した理由
- StarkEx L2統合: 決済レイヤーとの互換性
- 否認防止: 署名がオーダー起源を証明
- 公開検証: 秘密鍵なしで検証可能
- 将来性: ゼロ知識証明との整合性
edgeXの設計判断:
- StarkEx L2との完全互換性を優先
- 公開鍵検証による透明性の確保
- ゼロ知識証明エコシステムとの親和性
アンチパターンと改善策
1. K_MODULUS mod演算を忘れる
問題:
// ❌ modを忘れると401エラー
hashInt := new(big.Int).SetBytes(hashBytes)
sig := ecdsa.Sign(hashInt, privateKey)
改善:
// ✅ 必ずK_MODULUSでmod
hashInt := new(big.Int).SetBytes(hashBytes)
hashInt.Mod(hashInt, K_MODULUS)
sig := ecdsa.Sign(hashInt, privateKey)
2. REST署名でFIELD_PRIMEを使用
問題: REST署名とL2署名でモジュラスが異なる
改善:
- REST署名:
K_MODULUS(群位数) - L2署名:
FIELD_PRIME(体の素数)
3. タイムスタンプのズレ
問題: NTP同期失敗で401エラー
改善:
serverTime := time.Now().Unix()
requestTime := timestamp / 1000
if abs(serverTime - requestTime) > 30 {
log.Printf("時刻ずれ検出: %d秒", abs(serverTime-requestTime))
}
参考リンク
- edgeX API Documentation
- Stark Curve Specification - PedersenハッシュとKeccak-256の使用例
- gnark-crypto - Consensys 暗号ライブラリ
- Keccak-256 - Ethereum 互換SHA3
まとめ
引き続き PerpDEX 関連での取引ボット開発の情報も発信していきます。いいねやフォローをいただけると幸いです!X (旧Twitter) のDMでもボット構築などに困っている方は連絡をいただけると、色々とサポート可能です。
Discussion