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"