JWK から Tapyrus::Key

JWK形式で表現された鍵をTapyrus::Keyオブジェクトとして扱いたい

require 'tapyrus' require 'json/jwt'

結論

秘密鍵から
jwk_hash_with_priv = { "kty": "EC", "crv": "secp256k1", "x": "Sp1zTvtooTckKLn1e5mZ1lRyOruVZen918HW3HQxbFc", "y": "OKGyUbaELSi4fbu0CeqkMkZEMrbjyDxx1cvQIcSO0Kw", "d": "zxHazfJ2WAiPsk6I16ek0jwv1hzqxXLDyrZqQCIMrB4" } jwk_with_priv = JSON::JWK.new(jwk_hash_with_priv) priv_key = Tapyrus::Key.new(priv_key: jwk_with_priv.to_key.private_key.to_s(16).encode('US-ASCII'), key_type: 0)
公開鍵から
jwk_hash = { "kty": "EC", "crv": "secp256k1", "x": "Sp1zTvtooTckKLn1e5mZ1lRyOruVZen918HW3HQxbFc", "y": "OKGyUbaELSi4fbu0CeqkMkZEMrbjyDxx1cvQIcSO0Kw" } jwk = JSON::JWK.new(jwk_hash) pubkey = Tapyrus::Key.new(pubkey: jwk.to_key.public_key.to_bn.to_s(16).downcase.encode('US-ASCII'), key_type: 0)
OP_CDSで検証
message = 'hogehoge' message_hex = message.bth digest = Tapyrus.sha256(message_hex) signature = priv_key.sign(digest) script_2 = Tapyrus::Script.new << signature << message_hex << pubkey.pubkey << OP_CHECKDATASIG script_2.run # => true script_1 = Tapyrus::Script.new << signature << message_hex << priv_key.pubkey << OP_CHECKDATASIG script_1.run # => true
まとめ
jwk = JSON::JWK.new(jwk_hash) # @params jwk [JSON::JWK] EC secp256k1 def jwk_to_tapyrus_key(jwk) key = jwk.to_key if key.private_key.nil? Tapyrus::Key.new(pubkey: key.public_key.to_bn.to_s(16).downcase.encode('US-ASCII'), key_type: 0) else Tapyrus::Key.new(priv_key: key.private_key.to_s(16).encode('US-ASCII'), key_type: 0) end end

以降は格闘したログ


秘密鍵から
jwk1 = { "kty": "EC", "crv": "secp256k1", "x": "Sp1zTvtooTckKLn1e5mZ1lRyOruVZen918HW3HQxbFc", "y": "OKGyUbaELSi4fbu0CeqkMkZEMrbjyDxx1cvQIcSO0Kw", "d": "zxHazfJ2WAiPsk6I16ek0jwv1hzqxXLDyrZqQCIMrB4" } jwk_key1 = JSON::JWK.new(jwk1).to_key key1 = Tapyrus::Key.new(priv_key: jwk_key1.private_key.to_s(16)) key1.pubkey # => "044A9D734EFB68A1372428B9F57B9999D654723ABB9565E9FDD7C1D6DC74316C5738A1B251B6842D28B87DBBB409EAA432464432B6E3C83C71D5CBD021C48ED0AC"
公開鍵から
jwk2 = { "kty": "EC", "crv": "secp256k1", "x": "Sp1zTvtooTckKLn1e5mZ1lRyOruVZen918HW3HQxbFc", "y": "OKGyUbaELSi4fbu0CeqkMkZEMrbjyDxx1cvQIcSO0Kw" } jwk_key2 = JSON::JWK.new(jwk2).to_key key2 = Tapyrus::Key.new(pubkey: jwk_key2.public_key.to_bn.to_s(16)) key2.pubkey # => "024a9d734efb68a1372428b9f57b9999d654723abb9565e9fdd7c1d6dc74316c57"

公開鍵違くね?

message = 'hogehoge' message_hex = message.bth digest = Tapyrus.sha256(message_hex) signature = key1.sign(digest) script = Tapyrus::Script.new << signature << message_hex << key2.pubkey << OP_CHECKDATASIG script.run # => false script = Tapyrus::Script.new << signature << message_hex << key1.pubkey << OP_CHECKDATASIG script.run # => true

だよね

リトライ

compressed の違いでは?key_type を指定してみる

秘密鍵から
jwk_hash_with_d = { "kty": "EC", "crv": "secp256k1", "x": "Sp1zTvtooTckKLn1e5mZ1lRyOruVZen918HW3HQxbFc", "y": "OKGyUbaELSi4fbu0CeqkMkZEMrbjyDxx1cvQIcSO0Kw", "d": "zxHazfJ2WAiPsk6I16ek0jwv1hzqxXLDyrZqQCIMrB4" } jwk1 = JSON::JWK.new(jwk_hash_with_d) key1 = Tapyrus::Key.new(priv_key: jwk1.to_key.private_key.to_s(16), key_type: 0) key1.pubkey # => "044a9d734efb68a1372428b9f57b9999d654723abb9565e9fdd7c1d6dc74316c5738a1b251b6842d28b87dbbb409eaa432464432b6e3c83c71d5cbd021c48ed0ac"
公開鍵から
jwk_hash = { "kty": "EC", "crv": "secp256k1", "x": "Sp1zTvtooTckKLn1e5mZ1lRyOruVZen918HW3HQxbFc", "y": "OKGyUbaELSi4fbu0CeqkMkZEMrbjyDxx1cvQIcSO0Kw" } jwk2 = JSON::JWK.new(jwk_hash) key2 = Tapyrus::Key.new(pubkey: jwk2.to_key.public_key.to_bn.to_s(16).downcase, key_type: 0) key2.pubkey # => "044a9d734efb68a1372428b9f57b9999d654723abb9565e9fdd7c1d6dc74316c5738a1b251b6842d28b87dbbb409eaa432464432b6e3c83c71d5cbd021c48ed0ac"
検証
key1.pubkey == key2.pubkey # => true message = 'hogehoge' message_hex = message.bth digest = Tapyrus.sha256(message_hex) signature = key1.sign(digest) script_2 = Tapyrus::Script.new << signature << message_hex << key2.pubkey << OP_CHECKDATASIG script_2.run # => false script_1 = Tapyrus::Script.new << signature << message_hex << key1.pubkey << OP_CHECKDATASIG script_1.run # => true

???

script_2.to_s # => "<sig> <message_hex> 30343461396437333465666236386131333732343238623966353762393939396436353437323361626239353635653966646437633164366463373433313663353733386131623235316236383432643238623837646262623430396561613433323436343433326236653363383363373164356362643032316334386564306163 OP_CHECKDATASIG" script_1.to_s # => "<sig> <message_hex> 044a9d734efb68a1372428b9f57b9999d654723abb9565e9fdd7c1d6dc74316c5738a1b251b6842d28b87dbbb409eaa432464432b6e3c83c71d5cbd021c48ed0ac OP_CHECKDATASIG"

なぜか script_2 の方だけ keyx.pubkey が .bth されてる

Tapyrus::Script の << の定義部分を見ると,エンコード形式によって bth される感じっぽいのでエンコードを見る

key2.pubkey.encoding # => #<Encoding:ASCII-8BIT> key1.pubkey.encoding # => #<Encoding:US-ASCII>

ほ〜〜〜ん

script_2 = Tapyrus::Script.new << signature << message_hex << key2.pubkey.encode('US-ASCII') << OP_CHECKDATASIG script_2.run # => true

!!!

エンコード形式の違いでした

なるほどつまりこの時点でやるべきか

key2 = Tapyrus::Key.new(pubkey: jwk2.to_key.public_key.to_bn.to_s(16).downcase.encode('US-ASCII'), key_type: 0) key1 = Tapyrus::Key.new(priv_key: jwk1.to_key.private_key.to_s(16).encode('US-ASCII'), key_type: 0)