Module: Contracthashtool
- Defined in:
- lib/contracthashtool.rb,
lib/contracthashtool/version.rb
Overview
Ruby port of github.com/Blockstream/contracthashtool
Defined Under Namespace
Modules: EC_ADD
Constant Summary collapse
- VERSION =
"0.0.1"
Class Method Summary collapse
-
.claim(private_key_wif, payee_address, nonce_hex) ⇒ Object
claim a contract.
-
.compute_data(address, nonce_hex) ⇒ Object
compute HMAC data.
-
.generate(redeem_script_hex, payee_address, nonce_hex = nil) ⇒ Object
generate a contract address.
Class Method Details
.claim(private_key_wif, payee_address, nonce_hex) ⇒ Object
claim a contract
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/contracthashtool.rb', line 35 def self.claim(private_key_wif, payee_address, nonce_hex) key = Bitcoin::Key.from_base58(private_key_wif) data = compute_data(payee_address, nonce_hex)[1] pubkey = [key.pub].pack("H*") tweak = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("SHA256"), pubkey, data).to_i(16) group = OpenSSL::PKey::EC::Group.new('secp256k1') raise "order exceeded, verify parameters" if tweak >= group.order derived_key = (tweak + key.priv.to_i(16)) % group.order Bitcoin::Key.new(derived_key.to_s(16)) end |
.compute_data(address, nonce_hex) ⇒ Object
compute HMAC data
49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/contracthashtool.rb', line 49 def self.compute_data(address, nonce_hex) nonce = nonce_hex ? [nonce_hex].pack("H32") : SecureRandom.random_bytes(16) hash160 = [Bitcoin.hash160_from_address(address)].pack("H*") address_type = Bitcoin.address_type(address) case address_type when :hash160 address_type = "P2PH" when :p2sh address_type = "P2SH" else raise "unsuppoorted address type #{address_type}" end [ nonce.unpack("H*")[0], address_type + nonce + hash160 ] end |
.generate(redeem_script_hex, payee_address, nonce_hex = nil) ⇒ Object
generate a contract address
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/contracthashtool.rb', line 9 def self.generate(redeem_script_hex, payee_address, nonce_hex=nil) redeem_script = Bitcoin::Script.new([redeem_script_hex].pack("H*")) raise "only multisig redeem scripts are currently supported" unless redeem_script.is_multisig? nonce_hex, data = compute_data(payee_address, nonce_hex) derived_keys = [] group = OpenSSL::PKey::EC::Group.new('secp256k1') redeem_script.get_multisig_pubkeys.each do |pubkey| tweak = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("SHA256"), pubkey, data).to_i(16) raise "order exceeded, pick a new nonce" if tweak >= group.order tweak = OpenSSL::BN.new(tweak.to_s) key = Bitcoin::Key.new(nil, pubkey.unpack("H*")[0]) key = key.instance_variable_get(:@key) point = group.generator.mul(tweak).add(key.public_key).to_bn.to_i key = Bitcoin::Key.new(nil, point.to_s(16)) key.instance_eval{ @pubkey_compressed = true } derived_keys << key.pub end m = redeem_script.get_signatures_required p2sh_script = Bitcoin::Script.to_p2sh_multisig_script(m, *derived_keys)[0] [ nonce_hex, Bitcoin::Script.new(p2sh_script).get_p2sh_address ] end |