Class: MoneyTree::PrivateKey

Inherits:
Key
  • Object
show all
Defined in:
lib/money-tree/key.rb

Constant Summary

Constants inherited from Key

Key::GROUP_NAME, Key::ORDER

Constants included from Support

Support::BASE58_CHARS, Support::INT32_MAX, Support::INT64_MAX

Instance Attribute Summary

Attributes inherited from Key

#ec_key, #key, #options, #raw_key

Instance Method Summary collapse

Methods inherited from Key

#to_bytes, #to_i, #valid?

Methods included from Support

#base58_to_int, #bytes_to_hex, #bytes_to_int, #decode_base58, #decode_base64, #digestify, #encode_base58, #encode_base64, #from_serialized_base58, #hex_to_bytes, #hex_to_int, #hmac_sha512, #hmac_sha512_hex, #int_to_base58, #int_to_bytes, #int_to_hex, #ripemd160, #sha256, #to_serialized_base58

Constructor Details

#initialize(opts = {}) ⇒ PrivateKey

Returns a new instance of PrivateKey.



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/money-tree/key.rb', line 39

def initialize(opts = {})
  @options = opts
  @ec_key = PKey::EC.new GROUP_NAME
  if @options[:key]
    @raw_key = @options[:key]
    @key = parse_raw_key
    import
  else
    generate
    @key = to_hex
  end
end

Instance Method Details

#base64_format?(base64_key = raw_key) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/money-tree/key.rb', line 120

def base64_format?(base64_key = raw_key)
  base64_key.length == 44 && base64_key =~ /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
end

#calculate_public_key(opts = {}) ⇒ Object



61
62
63
64
65
66
# File 'lib/money-tree/key.rb', line 61

def calculate_public_key(opts = {})
  opts[:compressed] = true unless opts[:compressed] == false
  group = ec_key.group
  group.point_conversion_form = opts[:compressed] ? :compressed : :uncompressed
  point = group.generator.mul ec_key.private_key
end

#compressed_wif_format?Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/money-tree/key.rb', line 106

def compressed_wif_format?
  wif_format?(:compressed)
end

#from_base64(base64_key = raw_key) ⇒ Object



101
102
103
104
# File 'lib/money-tree/key.rb', line 101

def from_base64(base64_key = raw_key)
  raise InvalidBase64Format unless base64_format?(base64_key)
  decode_base64(base64_key)
end

#from_hex(hex = raw_key) ⇒ Object



89
90
91
# File 'lib/money-tree/key.rb', line 89

def from_hex(hex = raw_key)
  hex
end

#from_integer(bignum = raw_key) ⇒ Object



84
85
86
87
# File 'lib/money-tree/key.rb', line 84

def from_integer(bignum = raw_key)
  # TODO: does this need a byte size specification?
  int_to_hex(bignum)
end

#from_wif(wif = raw_key) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/money-tree/key.rb', line 93

def from_wif(wif = raw_key)
  compressed = wif.length == 52
  validate_wif(wif)
  hex = decode_base58(wif)
  last_char = compressed ? -11 : -9
  hex.slice(2..last_char)
end

#generateObject



52
53
54
# File 'lib/money-tree/key.rb', line 52

def generate
  ec_key.generate_key
end

#hex_format?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/money-tree/key.rb', line 124

def hex_format?
  raw_key.length == 64 && !raw_key[/\H/]
end

#importObject



56
57
58
59
# File 'lib/money-tree/key.rb', line 56

def import
  ec_key.private_key = BN.new(key, 16)
  set_public_key
end

#parse_raw_keyObject



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/money-tree/key.rb', line 72

def parse_raw_key
  result = if raw_key.is_a?(Integer) then from_integer
  elsif hex_format? then from_hex
  elsif base64_format? then from_base64
  elsif compressed_wif_format? then from_wif
  elsif uncompressed_wif_format? then from_wif
  else
    raise KeyFormatNotFound
  end
  result.downcase
end

#set_public_key(opts = {}) ⇒ Object



68
69
70
# File 'lib/money-tree/key.rb', line 68

def set_public_key(opts = {})
  ec_key.public_key = calculate_public_key(opts)
end

#to_base64Object



156
157
158
# File 'lib/money-tree/key.rb', line 156

def to_base64
  encode_base64(to_hex)
end

#to_hexObject



128
129
130
# File 'lib/money-tree/key.rb', line 128

def to_hex
  int_to_hex @ec_key.private_key, 64
end

#to_s(network: :bitcoin) ⇒ Object



160
161
162
# File 'lib/money-tree/key.rb', line 160

def to_s(network: :bitcoin)
  to_wif(network: network)
end

#to_wif(compressed: true, network: :bitcoin) ⇒ Object



132
133
134
135
136
137
138
139
140
# File 'lib/money-tree/key.rb', line 132

def to_wif(compressed: true, network: :bitcoin)
  source = NETWORKS[network][:privkey_version] + to_hex
  source += NETWORKS[network][:privkey_compression_flag] if compressed
  hash = sha256(source)
  hash = sha256(hash)
  checksum = hash.slice(0..7)
  source_with_checksum = source + checksum
  encode_base58(source_with_checksum)
end

#uncompressed_wif_format?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/money-tree/key.rb', line 110

def uncompressed_wif_format?
  wif_format?(:uncompressed)
end

#validate_wif(wif) ⇒ Object

Raises:



152
153
154
# File 'lib/money-tree/key.rb', line 152

def validate_wif(wif)
  raise InvalidWIFFormat unless wif_valid?(wif)
end

#wif_format?(compression) ⇒ Boolean

Returns:

  • (Boolean)


114
115
116
117
118
# File 'lib/money-tree/key.rb', line 114

def wif_format?(compression)
  length = compression == :compressed ? 52 : 51
  wif_prefixes = MoneyTree::NETWORKS.map {|k, v| v["#{compression}_wif_chars".to_sym]}.flatten
  raw_key.length == length && wif_prefixes.include?(raw_key.slice(0))
end

#wif_valid?(wif) ⇒ Boolean

Returns:

  • (Boolean)


142
143
144
145
146
147
148
149
150
# File 'lib/money-tree/key.rb', line 142

def wif_valid?(wif)
  hex = decode_base58(wif)
  checksum = hex.chars.to_a.pop(8).join
  source = hex.slice(0..-9)
  hash = sha256(source)
  hash = sha256(hash)
  hash_checksum = hash.slice(0..7)
  checksum == hash_checksum
end