Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

ECDSA(secp256k1)での署名と検証をrubyで行う(ecdsaライブラリ使用)

ECDSAでの署名と検証をrubyで行います。

ECDSAの仕様はこちらです。
ECDSA(楕円曲線デジタル署名アルゴリズム)の概要 - Pebble Coding

それではコードです。

#!/usr/bin/env ruby

require 'ecdsa'
require 'securerandom'
require 'digest'

def bin_to_hex(s)
  s.each_byte.map { |b| b.to_s(16) }.join
end

group = ECDSA::Group::Secp256k1
n = group.order
p "group order:#{n}"

#sk = 1 + SecureRandom.random_number(n-1)
sk = 3 
pk = group.generator.multiply_by_scalar(sk)

p "sk:"
p sk
p "pk:"
p pk

# sign
msg = "0000"
msg_digest = Digest::SHA256::digest(msg)
#nonce = 1 + SecureRandom.random_number(n-1)
nonce = 2 
sig = ECDSA.sign(group,sk,msg_digest,nonce)

p "msg_digest:#{msg_digest}"
p "nonce:#{nonce}"
p "sig.r:#{sig.r},#{sig.r.to_s(16)}"
p "sig.s:#{sig.s},#{sig.s.to_s(16)}"

sig_der = ECDSA::Format::SignatureDerString.encode(sig)

p "sig_der:#{sig_der}"
p "sig_def(hex):#{bin_to_hex(sig_der)}"

# verify
v_digest = OpenSSL::Digest::SHA256.digest(msg)
v_sig = ECDSA::Format::SignatureDerString.decode(sig_der)
result = ECDSA.valid_signature?(pk, v_digest, sig)
p "result:#{result}"

秘密鍵とNonceは通常ランダムに取りますが、ここでは他のライブラリの動作との確認を行いたいので、 秘密鍵は3,Nonceは2としています。

ECDSAの署名を行うライブラリはこちらになります。

https://github.com/DavidEGrayson/ruby_ecdsa

secp256k1のベースポイントGを秘密鍵分だけスカラー倍した点がpk(公開鍵)になります。
メッセージ文字列"0000"をSHA256したバイト列をBigEndianで数値としてものに対して署名します。
BigEndianであることは
AMERICAN NATIONAL STANDARD X9.62-1998
の 4.3.2 Octet-String-to-Integer Conversion の章や
SEC 1: Elliptic Curve Cryptography
の 2.3.8 Octet-String-to-Integer Conversion の章に記述があります。

(r, s)のペアである署名sigと公開鍵(点pk)を使って、メッセージと署名の組みが正しいことを確認しています。

"group order:115792089237316195423570985008687907852837564279074904382605163141518161494337"
"sk:"
3
"pk:"
#<ECDSA::Point: secp256k1, 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9, 0x388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672>
"msg_digest:\x9A\xF1[3nj\x96\x19\x92\x857\xDF0\xB2\xE6\xA27ei\xFC\xF9\xD7\xE7s\xEC\xCE\xDEe`e)\xA0"
"nonce:2"
"sig.r:89565891926547004231252920425935692360644145829622209833684329913297188986597,c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
"sig.s:111494102406131234412316855906883406462147064785892425994642684023738105619079,f67f6cf81a19873091aa7c9578fa2e96490e9bfc78ae7e9798004e8252c06287"
"sig_der:0F\x02!\x00\xC6\x04\x7F\x94A\xED}m0E@n\x95\xC0|\xD8\\w\x8EK\x8C\xEF<\xA7\xAB\xAC\t\xB9\\p\x9E\xE5\x02!\x00\xF6\x7Fl\xF8\x1A\x19\x870\x91\xAA|\x95x\xFA.\x96I\x0E\x9B\xFCx\xAE~\x97\x98\x00N\x82R\xC0b\x87"
"sig_def(hex):30462210c647f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac9b95c709ee52210f67f6cf81a19873091aa7c9578fa2e9649e9bfc78ae7e979804e8252c06287"
"result:true"

参考:
http://www.secg.org/sec1-v2.pdf