楕円曲線DSA

楕円曲線DSA（だえんきょくせんDSA、Elliptic Curve Digital Signature Algorithm、Elliptic Curve DSA、楕円DSA、ECDSA）は、Digital Signature Algorithm (DSA) について楕円曲線暗号を用いるようにした変種である。 楕円曲線暗号で一般的に言われるように、ECDSAにおいて必要とされる公開鍵のサイズはセキュリティビット数のおよそ2倍であると考えられている。例えば、80ビットのセキュリティビット数（攻撃者が秘密鍵を取得するために 2 80 {\displaystyle 2^{80}} 回の計算を必要とする）を得るために、DSAでは最低でも1024ビットの公開鍵が必要であるが、ECDSAでは160ビットの公開鍵で十分である。一方、署名のサイズはDSAでもECDSAでも同じであり、必要とするビット安全性の4倍のビット長を要する（80ビットのビット安全性を保つためには320ビットの長さの署名が必要）。 アリスが署名したメッセージをボブに送る場合を考える。最初に、使用する楕円曲線のパラメータ ( C U R V E , G , n ) {\displaystyle (CURVE,G,n)} を決めておく必要がある。 アリスは [ 1 , n − 1 ] {\displaystyle [1,n-1]} の範囲からランダムに選択された秘密鍵 d A {\displaystyle d_{A}} と、公開鍵 Q A = d A ∗ G {\displaystyle Q_{A}=d_{A}*G} から成る鍵ペアを生成する。ここで ∗ {\displaystyle *} は楕円曲線上での掛け算 (scalar multiplication) を意味する。 アリスがメッセージ m {\displaystyle m} に署名する場合、以下の計算を行う。 e = HASH ( m ) {\displaystyle e={\textrm {HASH}}(m)} を計算する。ここで HASH はSHA-1のような暗号学的ハッシュ関数を指す。 z {\displaystyle z} を、 e {\displaystyle e} の最上位側の L n {\displaystyle L_{n}} ビットとする。ここで L n {\displaystyle L_{n}} は位数 n {\displaystyle n} のビット長とする。 [ 1 , n − 1 ] {\displaystyle [1,n-1]} の範囲から整数 k {\displaystyle k} を任意に選択する。 曲線上の点 ( x 1 , y 1 ) = k ∗ G {\displaystyle (x_{1},y_{1})=k*G} を計算する。 r = x 1 mod n {\displaystyle r=x_{1}\,{\bmod {\,}}n} を計算する。 r = 0 {\displaystyle r=0} となる場合には k {\displaystyle k} の選択に戻る。 s = k − 1 ( z + r d A ) mod n {\displaystyle s=k^{-1}(z+rd_{A})\,{\bmod {\,}}n} を計算する。 s = 0 {\displaystyle s=0} となる場合には k {\displaystyle k} の選択に戻る。 ( r , s ) {\displaystyle (r,s)} が m {\displaystyle m} に対する署名となる。 s {\displaystyle s} を計算する際に、 HASH ( m ) {\displaystyle {\textrm {HASH}}(m)} から得られる z {\displaystyle z} は整数に変換される。 z {\displaystyle z} は n {\displaystyle n} より「大きい」ことは許されるが、「長い」ことは許されない。 DSAと同様に、署名ごとに異なる k {\displaystyle k} を選択することは極めて重要である。さもないと、ステップ6の式から秘密鍵 d A {\displaystyle d_{A}} を得ることが可能となってしまう。メッセージ m {\displaystyle m} および m ′ {\displaystyle m'} に対して、未知だが同じ k {\displaystyle k} から得られた2つの署名 ( r , s ) {\displaystyle (r,s)} および ( r , s ′ ) {\displaystyle (r,s')} がある場合、攻撃者は z {\displaystyle z} および z ′ {\displaystyle z'} を計算することが可能であり、 s − s ′ = k − 1 ( z − z ′ ) {\displaystyle s-s'=k^{-1}(z-z')} であることから、 k = z − z ′ s − s ′ {\displaystyle k={\frac {z-z'}{s-s'}}} が得られる。 s = k − 1 ( z + r d A ) {\displaystyle s=k^{-1}(z+rd_{A})} であるから、攻撃者は秘密鍵 d A = s k − z r {\displaystyle d_{A}={\frac {sk-z}{r}}} を得ることができる。このように単一の k {\displaystyle k} を用いることは不適切な実装であり、PlayStation 3のソフトウェア署名鍵が漏洩したのはこれが原因であった。 ボブがアリスの署名を検証するためには、アリスの公開鍵 Q A {\displaystyle Q_{A}} が必要である。公開鍵 Q A {\displaystyle Q_{A}} が正当なものであるかの検証は以下のとおりである。 Q A {\displaystyle Q_{A}} が O {\displaystyle O} でないことを確認する。 Q A {\displaystyle Q_{A}} が曲線上にあることを確認する。 n ∗ Q A = O {\displaystyle n*Q_{A}=O} であることを確認する。 メッセージ m {\displaystyle m} と署名 ( r , s ) {\displaystyle (r,s)} の検証は以下のように行われる。 r {\displaystyle r} および s {\displaystyle s} がいずれも [ 1 , n − 1 ] {\displaystyle [1,n-1]} の範囲にある整数であることを確認する。これを満たさない場合には署名は不正なものである。 e = HASH ( m ) {\displaystyle e={\textrm {HASH}}(m)} を計算する。ここで HASH は署名生成に用いられたハッシュ関数と同一のものである。 z {\displaystyle z} を、 e {\displaystyle e} の最上位側の L n {\displaystyle L_{n}} ビットとする。 w = s − 1 mod n {\displaystyle w=s^{-1}\,{\bmod {\,}}n} を計算する。 u 1 = z w mod n {\displaystyle u_{1}=zw\,{\bmod {\,}}n} および u 2 = r w mod n {\displaystyle u_{2}=rw\,{\bmod {\,}}n} を計算する。 曲線上の点 ( x 1 , y 1 ) = u 1 ∗ G + u 2 ∗ Q A {\displaystyle (x_{1},y_{1})=u_{1}*G+u_{2}*Q_{A}} を計算する。 r ≡ x 1 ( mod n ) {\displaystyle r\equiv x_{1}{\pmod {n}}} であれば署名は正当なものである。 Straus's algorithm（Shamir's trickとも）を用いることで、2つの楕円曲線上での掛け算の和 u 1 ∗ G + u 2 ∗ Q A {\displaystyle u_{1}*G+u_{2}*Q_{A}} を、2つの楕円曲線上での掛け算よりも速く計算することができる。 ここで C {\displaystyle C} は署名検証のステップ6で得られた点とする。 C = u 1 ∗ G + u 2 ∗ Q A {\displaystyle C=u_{1}*G+u_{2}*Q_{A}} 公開鍵が Q A = d A ∗ G {\displaystyle Q_{A}=d_{A}*G} と定義されることより C = u 1 ∗ G + u 2 d A ∗ G {\displaystyle C=u_{1}*G+u_{2}d_{A}*G} 楕円曲線上での掛け算より C = ( u 1 + u 2 d A ) ∗ G {\displaystyle C=(u_{1}+u_{2}d_{A})*G} 署名検証のステップ4より u 1 {\displaystyle u_{1}} および u 2 {\displaystyle u_{2}} の定義を拡張すると C = ( z s − 1 + r d A s − 1 ) ∗ G {\displaystyle C=(zs^{-1}+rd_{A}s^{-1})*G} s − 1 {\displaystyle s^{-1}} を外に出して C = ( z + r d A ) s − 1 ∗ G {\displaystyle C=(z+rd_{A})s^{-1}*G} 署名のステップ6より s {\displaystyle s} の定義を拡張すると C = ( z + r d A ) ( z + r d A ) − 1 ( k − 1 ) − 1 ∗ G {\displaystyle C=(z+rd_{A})(z+rd_{A})^{-1}(k^{-1})^{-1}*G} 逆数の逆数は元と同じであることと、逆数と元の積は O {\displaystyle O} であることから C = k ∗ G {\displaystyle C=k*G} r {\displaystyle r} の定義より、これは署名検証のステップ6と等しい。 これは正しく署名されたメッセージは正しく検証されることのみを示しており、セキュアな署名アルゴリズムであるための他の要素については考慮していない。 2010年12月、fail0verflowと名乗るグループが、ソニーがPlayStation 3のソフトウェア署名に用いていたECDSA秘密鍵の回復に成功したと発表した。しかし、これは k {\displaystyle k} をランダムではなく固定値としていたソニーの不適切な実装によるものであり、アルゴリズム自体の脆弱性ではない。署名生成のセクションで述べたように、 k {\displaystyle k} を固定値で用いることは秘密鍵 d A {\displaystyle d_{A}} を計算可能とし、アルゴリズムを破綻させるものである。 2011年3月29日、2人の研究者による論文がIACR（英語版）に発表された。この論文では、サイドチャネル攻撃の一つであるタイミング攻撃によって、ECDSAを認証に利用し、OpenSSLを用いたサーバのTLS秘密鍵を入手可能であることが示された。この脆弱性はOpenSSL 1.0.0eで修正された。 2013年8月、Java class SecureRandomのいくつかの実装において、 k {\displaystyle k} のコリジョンが発生することがあるバグが明らかとなった。前述のように、これにより秘密鍵を得ることが可能であり、Javaを利用しECDSAを認証に用いていたAndroidアプリからBitcoinが盗まれる危険性があった。この問題は、RFC 6979にあるように、秘密鍵とメッセージハッシュから決定論的に k {\displaystyle k} を導くことで回避できる。 このアルゴリズムは楕円曲線をパラメータとして必要とするが、多くの場合NISTによって定められた楕円曲線（P-256、P-384、P-521など）が用いられる。これらの曲線は特定のシード値からSHA-1を基盤としたアルゴリズムを用いて算出されているが、シード値の根拠が不明であること、また同じく固定の楕円曲線を用いたアルゴリズムであるDual_EC_DRBG（英語版）にNSAがバックドアを仕込んだ上でRSAセキュリティ社のセキュリティ製品に採用させたと報道されたことから、疑いの目で見られることがある。 ECDSAをサポートしているライブラリは以下の通りである。 Botan Bouncy Castle（英語版） cryptlib（英語版） Crypto++（英語版） libgcrypt（英語版） OpenSSL GnuTLS wolfCrypt