Class: Bitcoin::Key

Inherits:
Object
  • Object
show all
Defined in:
lib/bitcoin/key.rb

Overview

Elliptic Curve key as used in bitcoin.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(privkey = nil, pubkey = nil, compressed = false) ⇒ Key

Create a new key with given privkey and pubkey.

Bitcoin::Key.new
Bitcoin::Key.new(privkey)
Bitcoin::Key.new(nil, pubkey)


35
36
37
38
39
40
# File 'lib/bitcoin/key.rb', line 35

def initialize privkey = nil, pubkey = nil, compressed = false
  @key = Bitcoin.bitcoin_elliptic_curve
  @pubkey_compressed = pubkey ? self.class.is_compressed_pubkey?(pubkey) : compressed
  set_priv(privkey)  if privkey
  set_pub(pubkey)  if pubkey
end

Class Method Details

.from_base58(str) ⇒ Object

Import private key from base58 fromat as described in en.bitcoin.it/wiki/Private_key#Base_58_Wallet_Import_format and en.bitcoin.it/wiki/Base58Check_encoding#Encoding_a_private_key. See also #to_base58



18
19
20
21
22
23
24
25
# File 'lib/bitcoin/key.rb', line 18

def self.from_base58(str)
  hex = Bitcoin.decode_base58(str)
  compressed = hex.size == 76
  version, key, flag, checksum = hex.unpack("a2a64a#{compressed ? 2 : 0}a8")
  raise "Invalid version"   unless version == Bitcoin.network[:privkey_version]
  raise "Invalid checksum"  unless Bitcoin.checksum(version + key + flag) == checksum
  key = new(key, nil, compressed)
end

.generateObject

Generate a new keypair.

Bitcoin::Key.generate


10
11
12
# File 'lib/bitcoin/key.rb', line 10

def self.generate
  k = new; k.generate; k
end

.recover_compact_signature_to_key(data, signature_base64) ⇒ Object

Thanks to whoever wrote pastebin.com/bQtdDzHx for help with compact signatures

Given data and a compact signature (65 bytes, base64-encoded to a larger string), recover the public components of the key whose private counterpart validly signed data.

If the signature validly signed data, create a new Key having the signing public key and address. Otherwise return nil.

Be sure to check that the returned Key matches the one you were expecting! Otherwise you are merely checking that someone validly signed the data.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/bitcoin/key.rb', line 140

def self.recover_compact_signature_to_key(data, signature_base64)
  signature = signature_base64.unpack("m0")[0]
  return nil if signature.size != 65

  version = signature.unpack('C')[0]
  return nil if version < 27 or version > 34
 
  compressed = (version >= 31) ? (version -= 4; true) : false

  hash = Bitcoin.bitcoin_signed_message_hash(data)
  pub_hex = Bitcoin::OpenSSL_EC.recover_public_key_from_signature(hash, signature, version-27, compressed)
  return nil unless pub_hex

  Key.new(nil, pub_hex)
end

.verify_message(address, signature, message) ⇒ Object



123
124
125
# File 'lib/bitcoin/key.rb', line 123

def self.verify_message(address, signature, message)
  Bitcoin.verify_message(address, signature, message)
end

Instance Method Details

#==(other) ⇒ Object



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

def == other
  self.priv == other.priv
end

#addrObject

Get the address corresponding to the public key.



96
97
98
# File 'lib/bitcoin/key.rb', line 96

def addr
  Bitcoin.hash160_to_address(hash160)
end

#compressedObject



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

def compressed
  @pubkey_compressed
end

#generateObject

Generate new priv/pub key.



43
44
45
# File 'lib/bitcoin/key.rb', line 43

def generate
  @key.generate_key
end

#hash160Object

Get the hash160 of the public key.



91
92
93
# File 'lib/bitcoin/key.rb', line 91

def hash160
  Bitcoin.hash160(pub)
end

#privObject

Get the private key (in hex).



48
49
50
51
# File 'lib/bitcoin/key.rb', line 48

def priv
  return nil  unless @key.private_key
  @key.private_key.to_hex.rjust(64, '0')
end

#priv=(priv) ⇒ Object

Set the private key to priv (in hex).



54
55
56
# File 'lib/bitcoin/key.rb', line 54

def priv= priv
  set_priv(priv)
end

#pubObject

Get the public key (in hex). In case the key was initialized with only a private key, the public key is regenerated.



61
62
63
# File 'lib/bitcoin/key.rb', line 61

def pub
  @pubkey_compressed ? pub_compressed : pub_uncompressed
end

#pub=(pub) ⇒ Object

Set the public key (in hex).



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

def pub= pub
  set_pub(pub)
end

#pub_compressedObject



65
66
67
68
69
70
71
72
# File 'lib/bitcoin/key.rb', line 65

def pub_compressed
  regenerate_pubkey unless @key.public_key
  return nil        unless @key.public_key
  @key.public_key.group.point_conversion_form = :compressed
  hex = @key.public_key.to_hex.rjust(66, '0')
  @key.public_key.group.point_conversion_form = :uncompressed
  hex
end

#pub_uncompressedObject



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

def pub_uncompressed
  regenerate_pubkey unless @key.public_key
  return nil        unless @key.public_key
  @key.public_key.group.point_conversion_form = :uncompressed
  @key.public_key.to_hex.rjust(130, '0')
end

#sign(data) ⇒ Object

Sign data with the key.

key1 = Bitcoin::Key.generate
sig = key.sign("some data")


103
104
105
# File 'lib/bitcoin/key.rb', line 103

def sign(data)
  @key.dsa_sign_asn1(data)
end

#sign_message(message) ⇒ Object



115
116
117
# File 'lib/bitcoin/key.rb', line 115

def sign_message(message)
  Bitcoin.sign_message(priv, pub, message)['signature']
end

#to_base58Object

Export private key to base58 format. See also Key.from_base58



158
159
160
161
162
163
# File 'lib/bitcoin/key.rb', line 158

def to_base58
  data = Bitcoin.network[:privkey_version] + priv
  data += "01"  if @pubkey_compressed
  hex  = data + Bitcoin.checksum(data)
  Bitcoin.int_to_base58( hex.to_i(16) )
end

#verify(data, sig) ⇒ Object

Verify signature sig for data.

key2 = Bitcoin::Key.new(nil, key1.pub)
key2.verify("some data", sig)


110
111
112
# File 'lib/bitcoin/key.rb', line 110

def verify(data, sig)
  @key.dsa_verify_asn1(data, sig)
end

#verify_message(signature, message) ⇒ Object



119
120
121
# File 'lib/bitcoin/key.rb', line 119

def verify_message(signature, message)
  Bitcoin.verify_message(addr, signature, message)
end