class Xgt::Ruby::Auth
Public Class Methods
canonical?(sig)
click to toggle source
# File lib/xgt/ruby.rb, line 188 def self.canonical?(sig) sig = sig.unpack('C*') !( ((sig[0] & 0x80 ) != 0) || ( sig[0] == 0 ) || ((sig[1] & 0x80 ) != 0) || ((sig[32] & 0x80 ) != 0) || ( sig[32] == 0 ) || ((sig[33] & 0x80 ) != 0) ) end
from_base_58(string)
click to toggle source
# File lib/xgt/ruby.rb, line 170 def self.from_base_58(string) unhexlify(Bitcoin.decode_base58(string)) end
generate_wallet_name(*public_keys)
click to toggle source
# File lib/xgt/ruby.rb, line 159 def self.generate_wallet_name(*public_keys) hashed = Digest::SHA256.hexdigest(public_keys.join('')) base58 = Base58.binary_to_base58([hashed].pack('H*'), :bitcoin, true) address_prefix = 'XGT' "#{address_prefix}#{base58[0...40]}" end
generate_wif(name, password, role)
click to toggle source
# File lib/xgt/ruby.rb, line 138 def self.generate_wif(name, password, role) brain_key = (name + role + password).strip.split(/[\t\n\v\f\r ]+/).join(' ') key = "\x80".b + Digest::SHA256.digest(brain_key) checksum = Digest::SHA256.digest(Digest::SHA256.digest(key))[0...4] to_base_58(key + checksum) end
hexlify(s)
click to toggle source
# File lib/xgt/ruby.rb, line 174 def self.hexlify(s) a = [] if s.respond_to?(:each_byte) s.each_byte { |b| a << sprintf('%02X', b) } else s.each { |b| a << sprintf('%02X', b) } end a.join.downcase end
random_wif()
click to toggle source
# File lib/xgt/ruby.rb, line 132 def self.random_wif() private_key = unhexlify('80' + SecureRandom.hex(32)) checksum = Digest::SHA256.digest( Digest::SHA256.digest(private_key) ).byteslice(0, 4) to_base_58(private_key + checksum) end
sign_transaction(rpc, txn, wifs, chain_id)
click to toggle source
# File lib/xgt/ruby.rb, line 89 def self.sign_transaction(rpc, txn, wifs, chain_id) # Get the last irreversible block number response = rpc.call('database_api.get_dynamic_global_properties', {}) chain_date = response['time'] + 'Z' last_irreversible_block_num = response['last_irreversible_block_num'] ref_block_num = (last_irreversible_block_num - 1) & 0xffff # Get ref block info to append to the transaction response = rpc.call('block_api.get_block_header', { 'block_num' => last_irreversible_block_num }) header = response['header'] head_block_id = (header && header['previous']) ? header['previous'] : '0000000000000000000000000000000000000000' ref_block_prefix = [head_block_id].pack('H*')[4...8].unpack('V').first expiration = (Time.parse(chain_date) + 600).iso8601.gsub(/Z$/, '') # Append ref block info to the transaction txn['ref_block_num'] = ref_block_num txn['ref_block_prefix'] = ref_block_prefix txn['expiration'] = expiration # Get a hex digest of the transactioon response = rpc.call('transaction_api.get_transaction_hex', [txn]) transaction_hex = response[0..-3] unhexed = unhexlify(chain_id + transaction_hex) digest_hex = Digest::SHA256.hexdigest(unhexed) private_keys = wifs.map { |wif| Bitcoin::Key.from_base58(wif) } ec = Bitcoin::OpenSSL_EC count = 0 sig = nil # Calculate signatures and add them to the transaction txn['signatures'] ||= [] private_keys.each do |private_key| loop do count += 1 # TODO: Periodically check that count doesn't spin out of control public_key_hex = private_key.pub digest = unhexlify(digest_hex) sig = ec.sign_compact(digest, private_key.priv, public_key_hex, false) next if public_key_hex != ec.recover_compact(digest, sig) break if canonical?(sig) end txn['signatures'] << hexlify(sig) end txn end
to_base_58(bytes)
click to toggle source
# File lib/xgt/ruby.rb, line 166 def self.to_base_58(bytes) Bitcoin.encode_base58(hexlify(bytes)) end
unhexlify(s)
click to toggle source
# File lib/xgt/ruby.rb, line 184 def self.unhexlify(s) s.split.pack('H*') end
wif_to_public_key(wif, address_prefix)
click to toggle source
# File lib/xgt/ruby.rb, line 145 def self.wif_to_public_key(wif, address_prefix) private_wif = unhexlify(Bitcoin.decode_base58(wif)) version = private_wif[0] checksum = private_wif[-4..-1] # TODO: Verify version and checksum private_key = private_wif[1...-4] big_num = OpenSSL::BN.new(hexlify(private_key).to_i(16)) group = OpenSSL::PKey::EC::Group.new('secp256k1') product = group.generator.mul(big_num).to_bn public_key_buffer = OpenSSL::PKey::EC::Point.new(group, product).to_octet_string(:compressed) checksum = Digest::RMD160.digest(public_key_buffer) address_prefix + to_base_58(public_key_buffer + checksum[0...4]) end