Module: Bitcoin::Util

Included in:
Bitcoin
Defined in:
lib/bitcoin.rb

Instance Method Summary (collapse)

Instance Method Details

- (Boolean) address_checksum?(address)

Returns:

  • (Boolean)


44
45
46
47
48
49
50
51
# File 'lib/bitcoin.rb', line 44

def address_checksum?(address)
  a = base58_to_int(address).to_s(16)
  if address_version == "00"
    Bitcoin.checksum( address_version + a[0...40] ) == a[-8..-1]
  else
    Bitcoin.checksum( a[0...42] ) == a[-8..-1]
  end
end

- (Object) address_version



28
29
30
# File 'lib/bitcoin.rb', line 28

def address_version
  Bitcoin::network[:address_version]
end

- (Object) base58_to_int(base58_val)



100
101
102
103
104
105
106
107
108
# File 'lib/bitcoin.rb', line 100

def base58_to_int(base58_val)
  alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  int_val, base = 0, alpha.size
  base58_val.reverse.each_char.with_index do |char,index|
    raise ArgumentError, 'Value not a valid Base58 String.' unless char_index = alpha.index(char)
    int_val += char_index*(base**index)
  end
  int_val
end

- (Object) bitcoin_elliptic_curve



142
143
144
# File 'lib/bitcoin.rb', line 142

def bitcoin_elliptic_curve
  ::OpenSSL::PKey::EC.new("secp256k1")
end

- (Object) bitcoin_hash(hex)



161
162
163
164
165
# File 'lib/bitcoin.rb', line 161

def bitcoin_hash(hex)
  Digest::SHA256.digest(
    Digest::SHA256.digest( [hex].pack("H*").reverse )
  ).reverse.unpack("H*")[0]
end

- (Object) bitcoin_mrkl(a, b)



167
# File 'lib/bitcoin.rb', line 167

def bitcoin_mrkl(a, b); bitcoin_hash(b + a); end

- (Object) block_hash(prev_block, mrkl_root, time, bits, nonce, ver)



169
170
171
172
173
# File 'lib/bitcoin.rb', line 169

def block_hash(prev_block, mrkl_root, time, bits, nonce, ver)
  h = "%08x%08x%08x%064s%064s%08x" %
        [nonce, bits, time, mrkl_root, prev_block, ver]
  bitcoin_hash(h)
end

- (Object) checksum(hex)

checksum is a 4 bytes sha256-sha256 hexdigest.



39
40
41
42
# File 'lib/bitcoin.rb', line 39

def checksum(hex)
  b = [hex].pack("H*") # unpack hex
  Digest::SHA256.hexdigest( Digest::SHA256.digest(b) )[0...8]
end

- (Object) decode_compact_bits(bits)

target compact bits (int) to bignum hex



111
112
113
114
115
116
117
# File 'lib/bitcoin.rb', line 111

def decode_compact_bits(bits)
  bytes = Array.new(size=((bits >> 24) & 255), 0)
  bytes[0] = (bits >> 16) & 255 if size >= 1
  bytes[1] = (bits >>  8) & 255 if size >= 2
  bytes[2] = (bits      ) & 255 if size >= 3
  bytes.map{|i| "%02x" % [i] }.join.rjust(64, '0')
end

- (Object) decode_target(target_bits)



133
134
135
136
137
138
139
140
# File 'lib/bitcoin.rb', line 133

def decode_target(target_bits)
  case target_bits
  when Fixnum
    [ decode_compact_bits(target_bits).to_i(16), target_bits ]
  when String
    [ target_bits.to_i(16), encode_compact_bits(target_bits) ]
  end
end

- (Object) encode_base58(hex)



85
86
87
# File 'lib/bitcoin.rb', line 85

def encode_base58(hex)
  int_to_base58( hex[0...64].to_i(16) )
end

- (Object) encode_compact_bits(target)

target bignum hex to compact bits (int)



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/bitcoin.rb', line 120

def encode_compact_bits(target)
  # bignum to bytes (bn2mpi) without OpenSSL::BN
  mpi   = [ target.to_i(16).to_s(16) ].pack("H*").unpack("C*")
  bytes = [ mpi.size+1, 0 ].pack("NC").unpack("C*") + mpi

  size = bytes.size - 4
  nbits = size << 24
  nbits |= (bytes[4] << 16) if size >= 1
  nbits |= (bytes[5] <<  8) if size >= 2
  nbits |= (bytes[6]      ) if size >= 3
  nbits
end

- (Object) generate_address



156
157
158
159
# File 'lib/bitcoin.rb', line 156

def generate_address
  prvkey, pubkey = generate_key
  [ pubkey_to_address(pubkey), prvkey, pubkey, hash160(pubkey) ]
end

- (Object) generate_key



146
147
148
149
# File 'lib/bitcoin.rb', line 146

def generate_key
  key = bitcoin_elliptic_curve.generate_key
  inspect_key( key )
end

- (Object) hash160(hex)

hash160 is a 20 bytes (160bits) rmd610-sha256 hexdigest.



33
34
35
36
# File 'lib/bitcoin.rb', line 33

def hash160(hex)
  bytes = [hex].pack("H*")
  Digest::RMD160.hexdigest Digest::SHA256.digest(bytes)
end

- (Object) hash160_from_address(address)



64
65
66
67
68
# File 'lib/bitcoin.rb', line 64

def hash160_from_address(address)
  return nil  unless address_checksum?(address)
  a = base58_to_int(address).to_s(16)
  address_version == "00" ? a[0...40] : a[2...42]
end

- (Object) hash160_to_address(hex)



74
75
76
77
78
79
# File 'lib/bitcoin.rb', line 74

def hash160_to_address(hex)
  hex = address_version + hex
  addr = encode_base58(hex + checksum(hex))
  addr = "1" + addr  if address_version == "00"
  addr
end

- (Object) hash_mrkl_tree(tx)



175
176
177
178
179
180
181
182
183
# File 'lib/bitcoin.rb', line 175

def hash_mrkl_tree(tx)
  chunks = [ tx.dup ]
  while chunks.last.size >= 2
    chunks << chunks.last.each_slice(2).map{|i|
      Bitcoin.bitcoin_mrkl( i[0], i[1] || i[0] )
    }
  end
  chunks.flatten
end

- (Object) htb(h)



26
# File 'lib/bitcoin.rb', line 26

def htb(h); [h].pack("H*"); end

- (Object) hth(h)



25
# File 'lib/bitcoin.rb', line 25

def hth(h); h.unpack("H*")[0]; end

- (Object) inspect_key(key)



151
152
153
154
# File 'lib/bitcoin.rb', line 151

def inspect_key(key)
  [ key.private_key.to_hex.rjust(64, '0'),
    key.public_key.to_hex.rjust(130, '0') ]
end

- (Object) int_to_base58(int_val)



89
90
91
92
93
94
95
96
97
98
# File 'lib/bitcoin.rb', line 89

def int_to_base58(int_val)
  alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  base58_val, base = '', alpha.size
  while(int_val >= base)
    mod = int_val % base
    base58_val = alpha[mod,1] + base58_val
    int_val = (int_val - mod)/base
  end
  alpha[int_val,1] + base58_val
end

- (Object) open_key(private_key, public_key)



196
197
198
199
200
201
# File 'lib/bitcoin.rb', line 196

def open_key(private_key, public_key)
  key  = bitcoin_elliptic_curve
  key.private_key = ::OpenSSL::BN.from_hex(private_key)
  key.public_key  = ::OpenSSL::PKey::EC::Point.from_hex(key.group, public_key)
  key
end

- (Object) pubkey_to_address(pubkey)



81
82
83
# File 'lib/bitcoin.rb', line 81

def pubkey_to_address(pubkey)
  hash160_to_address( hash160(pubkey) )
end

- (Object) sha256(hex)



70
71
72
# File 'lib/bitcoin.rb', line 70

def sha256(hex)
  Digest::SHA256.hexdigest([hex].pack("H*"))
end

- (Object) sign_data(key, data)



186
187
188
# File 'lib/bitcoin.rb', line 186

def sign_data(key, data)
  key.dsa_sign_asn1(data)
end

- (Boolean) valid_address?(address)

TODO

Returns:

  • (Boolean)


53
54
55
56
57
58
59
60
61
62
# File 'lib/bitcoin.rb', line 53

def valid_address?(address) # TODO
  if address_version == "00"
    return false if address[0] != "1"
  else
    a = base58_to_int(address).to_s(16)
    return false if a[0..1] != address_version
  end
  return false if !address_checksum?(address)
  true
end

- (Object) verify_signature(hash, signature, public_key)



190
191
192
193
194
# File 'lib/bitcoin.rb', line 190

def verify_signature(hash, signature, public_key)
  key  = bitcoin_elliptic_curve
  key.public_key = ::OpenSSL::PKey::EC::Point.from_hex(key.group, public_key)
  key.dsa_verify_asn1(hash, signature)
end