Class: Xgt::Ruby::Auth
- Inherits:
-
Object
- Object
- Xgt::Ruby::Auth
- Defined in:
- lib/xgt/ruby.rb
Class Method Summary collapse
- .canonical?(sig) ⇒ Boolean
- .from_base_58(string) ⇒ Object
- .generate_wallet_name(*public_keys) ⇒ Object
- .generate_wif(name, password, role) ⇒ Object
- .hexlify(s) ⇒ Object
- .random_wif ⇒ Object
- .sign_transaction(rpc, txn, wifs, chain_id) ⇒ Object
- .to_base_58(bytes) ⇒ Object
- .unhexlify(s) ⇒ Object
- .wif_to_public_key(wif, address_prefix) ⇒ Object
Class Method Details
.canonical?(sig) ⇒ Boolean
188 189 190 191 192 193 194 195 196 197 |
# 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) ⇒ Object
170 171 172 |
# File 'lib/xgt/ruby.rb', line 170 def self.from_base_58(string) unhexlify(Bitcoin.decode_base58(string)) end |
.generate_wallet_name(*public_keys) ⇒ Object
159 160 161 162 163 164 |
# 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) ⇒ Object
138 139 140 141 142 143 |
# 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) ⇒ Object
174 175 176 177 178 179 180 181 182 |
# 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 ⇒ Object
132 133 134 135 136 |
# 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) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# 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) ⇒ Object
166 167 168 |
# File 'lib/xgt/ruby.rb', line 166 def self.to_base_58(bytes) Bitcoin.encode_base58(hexlify(bytes)) end |
.unhexlify(s) ⇒ Object
184 185 186 |
# File 'lib/xgt/ruby.rb', line 184 def self.unhexlify(s) s.split.pack('H*') end |
.wif_to_public_key(wif, address_prefix) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 |
# 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 |