class Bitcoin::Wallet::MasterKey

HD Wallet master seed

Attributes

encrypted[RW]
mnemonic[RW]
salt[RW]
seed[R]

Public Class Methods

generate() click to toggle source

generate new master key. @return Bitcoin::Wallet::MasterKey

# File lib/bitcoin/wallet/master_key.rb, line 25
def self.generate
  entropy = SecureRandom.hex(32)
  mnemonic = Bitcoin::Mnemonic.new('english')
  self.recover_from_words(mnemonic.to_mnemonic(entropy))
end
new(seed, salt: '', encrypted: false, mnemonic: nil) click to toggle source
# File lib/bitcoin/wallet/master_key.rb, line 16
def initialize(seed, salt: '', encrypted: false, mnemonic: nil)
  @mnemonic = mnemonic
  @seed = seed
  @encrypted = encrypted
  @salt = salt
end
parse_from_payload(payload) click to toggle source

parse master key raw data @param [String] payload raw data @return [Bitcoin::Wallet::MasterKey]

# File lib/bitcoin/wallet/master_key.rb, line 43
def self.parse_from_payload(payload)
  flag, payload = unpack_var_int(payload)
  raise 'encrypted flag is invalid.' unless [0, 1].include?(flag)
  salt, payload = unpack_var_string(payload)
  salt = '' unless salt
  seed, payload = unpack_var_string(payload)
  self.new(seed.bth, salt: salt.bth, encrypted: flag == 1)
end
recover_from_words(words) click to toggle source

recover master key from mnemonic word list. @param [Array] words the mnemonic word list. @return Bitcoin::Wallet::MasterKey

# File lib/bitcoin/wallet/master_key.rb, line 34
def self.recover_from_words(words)
  mnemonic = Bitcoin::Mnemonic.new('english')
  seed = mnemonic.to_seed(words)
  self.new(seed, mnemonic: words)
end

Public Instance Methods

decrypt(passphrase) click to toggle source

decrypt seed

# File lib/bitcoin/wallet/master_key.rb, line 89
def decrypt(passphrase)
  raise 'The wallet is not encrypted.' unless encrypted
  dec = OpenSSL::Cipher.new('AES-256-CBC')
  dec.decrypt
  dec.key, dec.iv = key_iv(dec, passphrase)
  decrypted_data = ''
  decrypted_data << dec.update(seed)
  decrypted_data << dec.final
  @seed = decrypted_data
  @encrypted = false
  @salt = ''
end
derive(path) click to toggle source

derive child key using derivation path. @return [Bitcoin::ExtKey]

# File lib/bitcoin/wallet/master_key.rb, line 68
def derive(path)
  derived_key = key
  parse_key_path(path).each{|num| derived_key = derived_key.derive(num)}
  derived_key
end
encrypt(passphrase) click to toggle source

encrypt seed

# File lib/bitcoin/wallet/master_key.rb, line 75
def encrypt(passphrase)
  raise 'The wallet is already encrypted.' if encrypted
  @salt = SecureRandom.hex(16)
  enc = OpenSSL::Cipher.new('AES-256-CBC')
  enc.encrypt
  enc.key, enc.iv = key_iv(enc, passphrase)
  encrypted_data = ''
  encrypted_data << enc.update(seed)
  encrypted_data << enc.final
  @seed = encrypted_data
  @encrypted = true
end
key() click to toggle source

get master key @return [Bitcoin::ExtKey] the master key

# File lib/bitcoin/wallet/master_key.rb, line 61
def key
  raise 'seed is encrypted. please decrypt the seed.' if encrypted
  Bitcoin::ExtKey.generate_master(seed)
end
to_payload() click to toggle source

generate payload with following format

encrypted(false:0, true:1)][salt(var str)][seed(var str)
# File lib/bitcoin/wallet/master_key.rb, line 54
def to_payload
  flg = encrypted ? 1 : 0
  pack_var_int(flg) << [salt, seed].map{|v|pack_var_string(v.htb)}.join
end

Private Instance Methods

key_iv(enc, passphrase) click to toggle source
# File lib/bitcoin/wallet/master_key.rb, line 104
def key_iv(enc, passphrase)
  key_iv = OpenSSL::PKCS5.pbkdf2_hmac_sha1(passphrase, salt, 2000, enc.key_len + enc.iv_len)
  [key_iv[0, enc.key_len], key_iv[enc.key_len, enc.iv_len]]
end