Giter Club home page Giter Club logo

money-tree's Introduction

MoneyTree

GitHub release (latest by date) Gem Gem GitHub top language

GitHub Workflow Status Code Coverage Code Climate GitHub

RSpec tested. Big Brother removed.

MoneyTree is a Ruby implementation of Bitcoin Wallets. Specifically, it supports Hierachical Deterministic wallets according to the protocol specified in BIP0032.


If you find this helpful, please consider a small Bitcoin donation to 1nj2kie1hATcFbAaD7dEY53QaxNgt4KBp.

Donate BTC


Why would I want an HD Wallet?

Hierarchical Deterministic (HD) Bitcoin Wallets offer several advantages over traditional Bitcoin wallets.

One of the problems with traditional Bitcoin wallets is that the wallet may hold a whole bunch of keypairs, each with Bitcoins attached to them. When you want to back up your wallet, you backup all of the current keys that you control in that wallet. However, if you later generate a new key, you need to make a brand new back up of your wallet. In fact, you need to back up your wallet every time you generate a new key.

Easy backups

HD wallets allow you to create a huge number of Bitcoin keys (keypairs) that all derive from a parent master key. This means that if you control the master key, you can generate the entire tree of children keys. So instead of needing to make repeated backups of your wallet, you can create a single backup when you create the wallet, and from then on to the end of time, you will never need to make a new backup, because you can just recreate ALL of the child keys from your master key.

Safely store your private keys offline

Additionally, HD wallets introduce cool new features to wallets, like being able to derive the entire tree of public keys from a parent public key without needing ANY private keys. For instance, let's say you have your master private key backed up on a paper wallet and stored offline in a safe somewhere, but you have the master public key available. Using just this public key, you can generate an entire tree of receive-only child public keys.

For instance, let's say you wanted to open a Bitcoin ecommerce website. With HD wallets, you can keep your master private key offline, and only put your public key onto the public webserver. Your website can then use that key to generate a receiving address for each and every product on your site, a unique address for each one of your customers, or even a key unique to each customer/product combo. (The uses are left up to your imagination.) And since the private key is stored offline, nobody will ever be able to hack your site and steal your Bitcoins.

Access controls

One bonus feature of HD Wallets is that they give you a lot of control over who in your organization has access to which keys. Like an organizational chart for a business, HD wallets are arranged in a tree formation. You could create whole branches of keypairs for each department in your organization, and by giving each department only the private key at the top of their department branch, each department will only be able to spend the coins on their branch. However, since you hold the master key, you can watch and spend ALL coins in the entire tree.

Accounting

Want to give your accountant access to view all transactions, but you don't want to give her access to spend any of your coins? No problem. You can simply give her the public key at any level in the tree that you desire, and she will be able to view transactions below that key in the tree, but won't be able to spend any of the coins.

Where can I learn more?

Installation

Add this line to your application's Gemfile:

gem 'money-tree'

And then execute:

$ bundle

Or install it yourself as:

$ gem install money-tree

Prerequisites

MoneyTree will only work with Ruby 2.0.0 and greater. This is because the version of OpenSSL included with previous versions of Ruby did not include an OpenSSL::PKey::EC::Point#mul (point multiplication) method, which is required in order to calculate a Bitcoin public key from a private key.

If you have a serious problem with this and REALLY need it to work on previous versions of Ruby, bring it up in the Issues section on Github, and I'll try to get to it. Or better yet, submit a pull request with matching spec! (Hint: you'll need to use FFI and the OpenSSL c library directly)

Usage

These instructions assume you have a decent understanding of how Bitcoin wallets operate and a cursory knowledge of how a Hierarchical Deterministic Bitcoin Wallet (HD Wallet) works.

Create a Master Node (seed)

To create a new HD Wallet, we're going to create a tree structure of private/public keypairs (nodes). You'll first want to start with a master node. This master node should be seeded with at least 16 random bytes but preferably 32 random bytes from a cryptographically secure PRNG (pseudo-random number generator).

DO NOT use a user generated password. Keep in mind that whoever controls the seed controls ALL coins in the entire tree, so it should not be left up to a human brain, because humans tend to follow patterns and patterns are subject to brute force attacks. Luckily, MoneyTree includes the seed generation by default so you don't need to create this on your own.

# Create a new master node (with automatic seed generation)
@master = MoneyTree::Master.new
=> MoneyTree::Master instance

@master.seed
=> "N\xC5\x9DD\xAA\xCC\x80a\a\x96%8\xC8\x86\x81\x90\t\x82&\xE4\x97Ay\xECs\xD8\xB1M\xEA\xE6|\xEF"

# Or import an existing seed
@master = MoneyTree::Master.new seed_hex: "000102030405060708090a0b0c0d0e0f"
=> MoneyTree::Master instance

@master.seed
=> "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0E\x0F"

Get info from a Node

MoneyTree::Master inherits from MoneyTree::Node, and you can do a lot of fun stuff with a node.

# Here are some things you can do with a node.
@master.index # The index is a sequential identifier in relation to its parent node. (i.e. the nth child of its parent)
=> 0

@master.depth # How many steps down the tree this node is. (The master node is at depth 0, its direct child is at depth 1, and so on...)
=> 0

@master.to_identifier
=> "3442193e1bb70916e914552172cd4e2dbc9df811"

@master.to_fingerprint
=> "3442193e"

@master.to_address
=> "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"

@master.private_key.to_hex
=> "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"

@master.private_key.to_wif
=> "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW"

@master.public_key.to_hex
=> "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"

@master.chain_code_hex
=> "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508" # Look up chain codes in the BIP0032 spec

@master.to_serialized_hex(:private)
=> "0488ade4000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d50800e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"

@master.to_bip32(:private)
=> "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"

@master.to_serialized_hex
=> "0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d5080339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"

@master.to_bip32
=> "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"

Generate a child Node

In HD Wallets, we refer to children nodes by their path in relation to the master node. This is determined using a slash-delimited string where each part of the delimited string represents a node in increasing depth. For instance, the path "m/0/3" walks down the tree starting with "m" the master key. The first part "m" represents the master key at depth 0. The next part "0" (i=0) represents the first child (sequentially) of "m" (depth 1). The last part "3" (i=3) represents the fourth child node of the previous node (depth 2), and so on down the line. You can create as many depths of nodes as you like.

To generate a child node from a given path:

@node = @master.node_for_path "m/0/3"
=> MoneyTree::Node instance

@node.index
=> 3

@node.depth
=> 2

@node.to_bip32(:private)
=> "xprv9ww7sMFLzJN15m7zX5JEBXQrQq8h4fU8PVqd929Hjy3xNSMzeBf163idMNBSq47DdCakyZTK7KcC2nbz3jqUkpJj8ZR4FqrijcFcFmcoBAe"

@node.to_bip32
=> "xpub6AvUGrnEpfvJJFCTd6qEYfMaxryBU8BykimDwQYuJJawFEh9BiyFdr37Cc4wEKCWWv7TsFQRUMdezXVqV9cfBUbeUEgNYCCP4omxULbNaRr"

Chain codes

In HD wallets, chain codes are the mathematical glue that binds a parent node to its child node. We use chain codes in order to create a mathematical relationship between a parent and its child. You don't necessarily need to understand how chain codes work because this library abstracts it for you, but you do at least need to know that for any given node, if you'd like to calculate its child node, you'll need three pieces of information. The parent node's key (either private or public), the sequential index value of i for the child and the parent node's chain code.

You don't need to worry about chain codes if you are creating or importing from a Master key (it's always the same for all HD wallet master keys), however if you are trying to import a derived child key at some lower depth in the tree, you'll need the chain code. Luckily, whenever we export a node to a wallet file, we encode it in a special format that includes all of the relevant info (including chain code) that we need to reconstruct the node in a single convenient serialized address.

Serialized Addresses

Because we need multiple pieces of info to reconstruct nodes in a tree, when we're dealing with HD wallets, we pass around a serialized address format that encodes both the key and the chain code. It looks like this:

# private key
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"

# public key
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"

In addition to the key and the chain code, this encoding also includes info about the depth and index of the key, along with a fingerprint of its parent key (which I presume is for quickly sorting a big pile of keys into a tree).

These are the addresses that you should use to represent each node in the tree structure, however these are NOT the bitcoin addresses you should pass around for receiving money. These are more for storing inside a wallet file so that you can reconstruct the tree.

To export a node to a serialized address, you can do:

@node.to_bip32(:private) # for private keys
=> "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"

@node.to_bip32
=> "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"

To import from a serialized address: (either public or private)

@node = MoneyTree::Node.from_bip32 "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"
=> MoneyTree::Node instance

Private derivation vs public derivation

You'll recall that HD Wallets allow us to generate an entire tree of private/public keypairs with a single parent private key. When we wish to generate child keypairs (that is, we want both the child private key and the child public key), we MUST have access to the parent private key. Using what's called "private derivation", we take the parent private key and its associated chain code along with a given index value (i.e. 0 = 1st child, 1 = 2nd child, (i-1) = ith child...), and we cryptomash™ them together to form a child private key and a new child chain code. This child key can then be used to generate its associated public key (in the same way we normally create Bitcoin public keys from private keys). The new chain code can be used to derive children of this child key and this process can keep repeating itself down the tree.

However, an added benefit of HD Wallets is that with JUST a public key, we can generate ALL public keys below that key. But how do we do this, since we don't have any private keys? We usually just put our private key in the Cryptomatic 2000 and out comes a public key. We accomplish this by using a second type of derivation called "public derivation". Using the power of a lot of math and elliptic curve formulae that look like it's straight out of Good Will Hunting, we can calculate the child public key directly from a parent public key. However, we cannot calculate the child private key. Therefore, if you only have a public key, you will only be able to derive other public keys. (That's a feature, not a bug.)

Export a public-key only node

Sometimes you don't want a node to contain any private key information. You can request that MoneyTree return you a node that is stripped of its private information by using a special notation in the path.

Either using a capital "M" instead of a lowercase "m", or by appending ".pub" to the end of the path, you will receive a node that is stripped of its private key.

For example:

@node = @master.node_for_path("M/0/3") # or "m/0/3.pub" or "M/0/3.pub"...these are equivalent

@node.to_bip32
=> "xpub6AvUGrnEpfvJJFCTd6qEYfMaxryBU8BykimDwQYuJJawFEh9BiyFdr37Cc4wEKCWWv7TsFQRUMdezXVqV9cfBUbeUEgNYCCP4omxULbNaRr"

@node.to_bip32(:private)
-> raises MoneyTree::Node::PrivatePublicMismatch error

Import a public-key only node

You can also import a node using only a public key. Keep in mind that this node will only be able to generate other public-key only nodes. You will not be able to derive child private keys using this node.

@node = MoneyTree::Node.from_bip32("xpub6AvUGrnEpfvJJFCTd6qEYfMaxryBU8BykimDwQYuJJawFEh9BiyFdr37Cc4wEKCWWv7TsFQRUMdezXVqV9cfBUbeUEgNYCCP4omxULbNaRr")
=> MoneyTree::Node instance

@node.to_bip32
=> "xpub6AvUGrnEpfvJJFCTd6qEYfMaxryBU8BykimDwQYuJJawFEh9BiyFdr37Cc4wEKCWWv7TsFQRUMdezXVqV9cfBUbeUEgNYCCP4omxULbNaRr"

@node.to_bip32(:private)
-> raises MoneyTree::Node::PrivatePublicMismatch error

Values of i and i-prime

Earlier we discussed the use of an index value i to represent the sequential ordinal index of a child in relation to its parent. That is, i=0 would be the first child, i=1 would be the second child, and so forth up to (i-1) as the i'th child. This index value is very important in the child key derivation process because it allows us to create a whole bunch of subnodes (child keys) for a given node, just by incrementing the i value. In fact, i is a 32-bit unsigned integer which gives us the ability to create up to 4,294,967,296 addresses for one node.

When choosing i values, the BIP0032 spec calls for using a reserved set of i values to denote a node that should use private derivation and another reserved set of i values to denote public derivation.

The way this breaks down is:

0 through 2,147,483,647 (i < 0x80000000) should use public derivation

2,147,483,648 through 4,294,967,295 (i >= 0x80000000) should use private derivation

Yikes, that's a lot of detail to remember. Luckily, there is a simple notation in the path strings that allow us to easily tell the difference between a node that uses public derivation and a node that uses private derivation. We use either " ' " (prime symbol) or "p" at the end of a node path part to denote private derivation.

For instance: "m/0'/1" and "m/0p/1" are equivalent and they translate to the "the second publicly derived child 1 of the first privately derived child 0 prime of the master key m". But since we know that the "first privately derived child" is in the i value range above 0x80000000, the very first possible i value in this range is actually 0x80000000, or 2,147,483,648. Therefore when we say "m/0p/1", what we really mean is "m/2147483648/1". Thus:

"m/0'/1" == "m/0p/1" == "m/2147483648/1"

They are all equivalent ways of saying the same thing, but the first two are just a more human readable shorthand notation. You are free to use whichever notation you prefer. This gem will parse it.

To add just a little more confusion to the mix, some wallets will use negative i values to also denote private derivation. Any i value that is negative will be processed using private derivation by this library. e.g. "m/-1/1". (NOTE: known issue, see below)

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Known Issues (PRs welcome)

  • Segwit (BIP49) address generation is not supported
  • Use of negative integers in paths does not produce the correct hardened derivation.

money-tree's People

Contributors

automatthew avatar drush avatar etscrivner avatar glitch003 avatar hstove avatar hudon avatar jvergeldedios avatar mgpnd avatar mhanne avatar nicoskaralis avatar nmarley avatar q9f avatar rickmark avatar semaj avatar thedoctor avatar wink avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

money-tree's Issues

Identifying BIP32 key network and key type

Given a BIP32 key, I'd like to figure out if it's a public or private key and on which network it's used. The information is in the key and the version info is already available in MoneyTrey::Network.

https://github.com/GemHQ/money-tree/blob/master/lib/money-tree/node.rb#L19 simply strips the version info from the key. I'd like to change that:

node = MoneyTree::Node.from_bip32("tpub...")
node.version
# => :bitcoin_testnet_pubkey

or

node = MoneyTree::Node.from_bip32("tpub...")
node.network
# => :bitcoin_testnet
node.key_type
# => :pubkey

Two questions:

  1. Would a pull request implementing the above be considered?
  2. What are your thoughts on one or two methods and methods names?

I'd be happy to test and implement these changes.

can't import to electrum or the other way

I always struggle here and tried both ways plenty of time

i use the rubygem "moneytree" and electrum 3.3

@master = MoneyTree::Master.new
@master.to_bip32(:private)

this will give me tprv8ZgxMBicQKsPe8hnfLVQdtZk2qMKnnDQs2ZKLgoJQBhedKQ5vB7srAb6Tk2iUYNkhaacTjNP9WzkbjCqPjk8ExUFGECbiR1Z8tZDs76jytn

however, i can't import this in electrum. the next button is just non active.


i tried the other way around and created a wallet with seed fabric body bright coffee special music virus raccoon side double shield shrug and exported the master public key which will gives me xpub661MyMwAqRbcGq54zC5FfD3rTjgcAGd36JvtW6r4RGheQjSdUVqAS9Q1DLAvzyvvxdYziZced4Y6kHLCqo73vuB4gGSpt6tJwtCWYm8zsBb

now i'll run the following

master_pub_key = "xpub661MyMwAqRbcGq54zC5FfD3rTjgcAGd36JvtW6r4RGheQjSdUVqAS9Q1DLAvzyvvxdYziZced4Y6kHLCqo73vuB4gGSpt6tJwtCWYm8zsBb"
$bitcoin_root_node = MoneyTree::Node.from_bip32(master_pub_key)

i = 0
20.times do
  p $bitcoin_root_node.node_for_path("m/0/#{i}").to_address
  i+= 1
end

all generated addresses will look like this

mpQPcBLyTqPPCw9dhdXYm3Dvnnn58Y4dwA
mt6UdprJNAuJUtG3BYWTy3dZrST7nZTwtZ

starting with a small M

however, in electrum all the addresses are starting with 1xxxxx

what am i doing wrong?

`money-tree` performs unsafe FFI and Monkey Patching of OpenSSL

There are two defects:

  1. By monkey patching OpenSSL::PKey::EC::Point this gem can cause error when other code performs EC operations on a curve other then secp256k1 - Do not monkey patch the OpenSSL library.
  2. By using FFI the gem might load two different libcyrpto binaries in the same process.

PR #43 solves both of these issues as well as provides a test to ensure conformance.

Support for Bitcoin only?

My apologies for the ignorant question as I can't find the answer elsewhere.

Do the wallets created by this gem only support BTC? I would like to use this for DOGE instead and am wondering if anything needs to be done differently or the addresses created will also work.

Unable to generate testnet addresses

I used to be able to retrieve testnet adresses...

master_node = "tpubD6NzVbkrYhZ4XhirPF9aBVXJ5jRXqEnvbNYjvT3A2TEJMS1WH98PJCQR7BKeDFm3qdYemwT4xroThSMj3G7s5RcGv1Eona6L2jajST7SRBx"
node_path = "m/0/1"
MoneyTree::Node.from_serialized_address(master_node).node_for_path(node_path).to_address
=> "mvrvQHJuUhXmbBuTJ9oXp34VsCjTQt2W3F"

This doesn't work anymore either with this syntax, or with the new "from_bip32" syntax, which are just synonyms anyway. Main net addresses are returned.

master_node = "tpubD6NzVbkrYhZ4XhirPF9aBVXJ5jRXqEnvbNYjvT3A2TEJMS1WH98PJCQR7BKeDFm3qdYemwT4xroThSMj3G7s5RcGv1Eona6L2jajST7SRBx"
node_path = "m/0/1"
MoneyTree::Node.from_serialized_address(master_node).node_for_path(node_path).to_address
=> "1GLy7EDvfg6Wp5Rqaaq9z7rB1D8kXdFWgo"

p2sh support

Does this support p2sh? For example, importing public keys several co-signers to derive addresses for the offline wallet

release lib money-tree v0.11.0 to rubygems.org

Hi @wink - if you have the time, please review the following release that removes unsafe ffi and monkey patching to openssl:

If possible, please consider release v0.11.0 to rubygems.org

Thank you 🙏🏼

Generate master node from private key

Is it possible to generate a master node from a private key instead of the seed? I generated a random node and want to save just the priv key and generate that same node from that key.

Ethereum Support

Can this be used for generating Ethereum addresses from a seed? Looks like some gems like this one are attempting it but I can't get their generated addresses to work properly. The addresses the gem I linked generates don't match the ones that MyEtherWallet or this tool would generate. I'm not experienced enough to know why though.

BIP49 (SegWit) derivation path

Address seems to be invalid calculated for BIP49 (SegWit) paths.

BIP49 Spec

Example:

https://iancoleman.github.io/bip39/

BIP39 Mnemonic:
romance exercise immense final promote blossom swamp strong village dinner salad target

Gives:
BIP44 Derivation Path - BIP32 Extended Public Key:
xpub6ENYRtaTwwoFKfA5CYHJ6sM27xRu6NJLjDG2W2ahVP9xQW65VEm4Rtf2grdCcjTvPYYhqqsctWuKgeydCwYnrySpiDMrhfDY8C81YzhjV3B
BIP49 Derivation Path - BIP32 Extended Public Key:
xpub6FQxoDQx1U5pdzp8CtRAnkoBUcebLrg7xazUZ6YfdyrWdGNEyHs8hZFt54uyKqUwxvjre7rrp2Bni59Ybok5FNmpFQaRRN8n7xBZbiNSBuQ

TEST OF BIP44 Derivation Path

m/44'/0'/0'/0/0 should be address 1NhXS3e19HeQhbzF3wvxSbM5KrEL18eiDF

node = MoneyTree::Node.from_bip32('xpub6ENYRtaTwwoFKfA5CYHJ6sM27xRu6NJLjDG2W2ahVP9xQW65VEm4Rtf2grdCcjTvPYYhqqsctWuKgeydCwYnrySpiDMrhfDY8C81YzhjV3B').node_for_path("0").to_address
=> "1NhXS3e19HeQhbzF3wvxSbM5KrEL18eiDF"

Success!

TEST OF BIP49 Derivation Path

m/49'/0'/0'/0/0 should be address 3HnFEPAxBpDfSMXNvKb3EgaBdkN89zc4gF

 node = MoneyTree::Node.from_bip32('xpub6FQxoDQx1U5pdzp8CtRAnkoBUcebLrg7xazUZ6YfdyrWdGNEyHs8hZFt54uyKqUwxvjre7rrp2Bni59Ybok5FNmpFQaRRN8n7xBZbiNSBuQ').node_for_path("0").to_address
=> "1JNtziN11HdS4HXAMUJzF511R4Cza7EPqA"

Fail! Address missmatch

Issue?

Am I doing / thinking wrong or has the Money Tree GEM a problem calculating BIP49 addresses?

Bech32 dependency

The gem on rubygems ( 0.11.1 / 0.11.0 ) is requiring bech32 dependency which is not present on gemspec.
Fix is already present on master, is it possible to publish a new version with this fix ?

Problem following Readme for importing public key

Hi
I tried to import a public key, but receive the error "undefined method to_fingerprint for nil:NilClass" creating the serialized address.
Here is what I did:
master = MoneyTree::Master.new
master.seed_hex #=> "abfe0d5341dffd5fb4fed0931a2acbc445deb6b87d72912e757b7f5e8237dc89"
n = master.node_for_path("m/0/1").to_serialized_address
n2 = MoneyTree::Node.from_serialized_address n
n2.to_serialized_address #=> explodes

Thanks a lot for your help!

litecoin support

hi

I think this should work for litecoin
litecoin: { address_version: '30', p2sh_version: '32', p2sh_char: '3',##TODO privkey_version: 'b0', privkey_compression_flag: '01',##TODO extended_privkey_version: "019d9cfe", extended_pubkey_version: "019da462", compressed_wif_chars: %w(K L),##TODO uncompressed_wif_chars: %w(5),##TODO protocol_version: 70002 }, litecoin_testnet: { address_version: '6f', p2sh_version: '3a', p2sh_char: '2',##TODO privkey_version: 'ef', privkey_compression_flag: '01',##TODO extended_privkey_version: "0436ef7d", extended_pubkey_version: "0436f6e1", compressed_wif_chars: %w(c),##TODO uncompressed_wif_chars: %w(9),##TODO protocol_version: 70002 }
could you add it to NETWORK ?
thanks

OpenSSL 3 deprecated RIPEMD160 ("legacy feature")

on ubuntu 20 with openssl 1.1 everything is ok
on ubuntu 22, since july 8th, with OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022), I have this error

 OpenSSL::Digest::DigestError:
   Digest initialization failed: initialization error
 # .rvm/gems/ruby-3.1.2@gems/money-tree-0.10.0/lib/money-tree/support.rb:62:in `digestify'
 # .rvm/gems/ruby-3.1.2@gems/money-tree-0.10.0/lib/money-tree/support.rb:70:in `ripemd160'
 # .rvm/gems/ruby-3.1.2@gems/money-tree-0.10.0/lib/money-tree/key.rb:246:in `to_ripemd160'
 # .rvm/gems/ruby-3.1.2@gems/money-tree-0.10.0/lib/money-tree/node.rb:130:in `to_identifier'
 # .rvm/gems/ruby-3.1.2@gems/money-tree-0.10.0/lib/money-tree/node.rb:146:in `to_address'
 # .rvm/gems/ruby-3.1.2@bundler/gems/cryptocoin_payable-776b48475f73/lib/cryptocoin_payable/adapters/bitcoin.rb:20:in `create_address'

[proposal] activate testnet mode via configuration

i've expected a configuration where we simply say

config.testnet = true

we then don't need to pass arguments into the address generation anymore

def to_serialized_hex(type = :public, network: :bitcoin)

could be changed to

 def to_serialized_hex(type = :public, network:  nil)
   network = config.network unless network

what would be against this idea?

would also benefit for testing purposes

Error when deploying to Heroku (Could not open library '/usr/lib/ssl')

I get the following error when I try to deploy a project to heroku with this gem as dependency:

2017-06-12T20:03:50.912570+00:00 app[web.1]: * Version 3.9.1 (ruby 2.3.1-p112), codename: Private Caller
2017-06-12T20:03:50.912540+00:00 app[web.1]: Puma starting in single mode...
2017-06-12T20:03:50.912571+00:00 app[web.1]: * Min threads: 5, max threads: 5
2017-06-12T20:03:50.912572+00:00 app[web.1]: * Environment: production
2017-06-12T20:03:52.571169+00:00 app[web.1]: ! Unable to load application: LoadError: Could not open library '/usr/lib/ssl': /usr/lib/ssl: cannot read file data: Is a directory.
2017-06-12T20:03:52.571196+00:00 app[web.1]: Could not open library 'libssl.so': libssl.so: cannot open shared object file: No such file or directory
2017-06-12T20:03:52.571379+00:00 app[web.1]: bundler: failed to load command: puma (/app/vendor/bundle/ruby/2.3.0/bin/puma)
2017-06-12T20:03:52.571474+00:00 app[web.1]: LoadError: Could not open library '/usr/lib/ssl': /usr/lib/ssl: cannot read file data: Is a directory.
2017-06-12T20:03:52.571476+00:00 app[web.1]: Could not open library 'libssl.so': libssl.so: cannot open shared object file: No such file or directory
2017-06-12T20:03:52.571477+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/ffi-1.9.18/lib/ffi/library.rb:147:in `block in ffi_lib'
2017-06-12T20:03:52.571477+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/ffi-1.9.18/lib/ffi/library.rb:100:in `map'
2017-06-12T20:03:52.571478+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/ffi-1.9.18/lib/ffi/library.rb:100:in `ffi_lib'
2017-06-12T20:03:52.571479+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/money-tree-0.9.0/lib/openssl_extensions.rb:9:in `<module:OpenSSLExtensions>'
2017-06-12T20:03:52.571480+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/money-tree-0.9.0/lib/openssl_extensions.rb:7:in `<module:MoneyTree>'
2017-06-12T20:03:52.571481+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/money-tree-0.9.0/lib/openssl_extensions.rb:6:in `<top (required)>'
2017-06-12T20:03:52.571481+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/money-tree-0.9.0/lib/money-tree.rb:1:in `require'
2017-06-12T20:03:52.571482+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/money-tree-0.9.0/lib/money-tree.rb:1:in `<top (required)>'
2017-06-12T20:03:52.571483+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler/runtime.rb:91:in `require'
2017-06-12T20:03:52.571483+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler/runtime.rb:91:in `block (2 levels) in require'
2017-06-12T20:03:52.571484+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler/runtime.rb:86:in `each'
2017-06-12T20:03:52.571485+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler/runtime.rb:86:in `block in require'
2017-06-12T20:03:52.571485+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler/runtime.rb:75:in `each'
2017-06-12T20:03:52.571486+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler/runtime.rb:75:in `require'
2017-06-12T20:03:52.571487+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.13.7/lib/bundler.rb:106:in `require'
2017-06-12T20:03:52.571488+00:00 app[web.1]:   /app/config/application.rb:7:in `<top (required)>'
2017-06-12T20:03:52.571488+00:00 app[web.1]:   /app/config/environment.rb:2:in `require_relative'
2017-06-12T20:03:52.571489+00:00 app[web.1]:   /app/config/environment.rb:2:in `<top (required)>'
2017-06-12T20:03:52.571490+00:00 app[web.1]:   config.ru:3:in `require_relative'
2017-06-12T20:03:52.571491+00:00 app[web.1]:   config.ru:3:in `block in <main>'
2017-06-12T20:03:52.571491+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:55:in `instance_eval'
2017-06-12T20:03:52.571492+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:55:in `initialize'
2017-06-12T20:03:52.571493+00:00 app[web.1]:   config.ru:in `new'
2017-06-12T20:03:52.571494+00:00 app[web.1]:   config.ru:in `<main>'
2017-06-12T20:03:52.571494+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:49:in `eval'
2017-06-12T20:03:52.571495+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:49:in `new_from_string'
2017-06-12T20:03:52.571496+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/rack-2.0.3/lib/rack/builder.rb:40:in `parse_file'
2017-06-12T20:03:52.571496+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/lib/puma/configuration.rb:313:in `load_rackup'
2017-06-12T20:03:52.571497+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/lib/puma/configuration.rb:242:in `app'
2017-06-12T20:03:52.571498+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/lib/puma/runner.rb:138:in `load_and_bind'
2017-06-12T20:03:52.571498+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/lib/puma/single.rb:87:in `run'
2017-06-12T20:03:52.571499+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/lib/puma/launcher.rb:174:in `run'
2017-06-12T20:03:52.571499+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/lib/puma/cli.rb:77:in `run'
2017-06-12T20:03:52.571500+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/gems/puma-3.9.1/bin/puma:10:in `<top (required)>'
2017-06-12T20:03:52.571501+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/bin/puma:23:in `load'
2017-06-12T20:03:52.571609+00:00 app[web.1]:   /app/vendor/bundle/ruby/2.3.0/bin/puma:23:in `<top (required)>'

It looks like the way this gem is loading the SSL lib is wrong.

https://github.com/GemHQ/money-tree/blob/master/lib/openssl_extensions.rb#L9

Wrong address from equivalents derivation path

According to the readme:

    "m/0'/1" == "m/0p/1" == "m/2147483648/1"

But I got this output:

master.node_for_path("m/0'/1").to_address
 => "1136fnhDPuJaA9KkSiZ29UGbwzdH1DYsfX"
master.node_for_path("m/0p/1").to_address
 => "1136fnhDPuJaA9KkSiZ29UGbwzdH1DYsfX"
master.node_for_path("m/2147483648/1").to_address
 => "14QqrtsnNZest6RTQVWxmbgDKSsveEGyx7"

And accourding to https://iancoleman.github.io/bip39/

m/2147483648/1 -> 1136fnhDPuJaA9KkSiZ29UGbwzdH1DYsfX

What am I missing?

ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]

gem list money-tree
money-tree (0.9.0)

0.1% of our addresses is wrongly generated

We use money-tree to maintain our wallet and generated around 30k+ addresses, each associated with a unique path
Recent audit revealed that there are 26 paths would generate a different address now compared to 6 months ago!

What could be the possible causes of this? Is there any way to recover the fund sent to old generated address? And how to prevent this from happening again?

Bip 32 test vector 5 fails 10/16

the following tests pass but should raise errors

it "recognizes pubkey version / prvkey mismatch" do
 MoneyTree::Node.from_bip32 "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm"
end

it "recognizes prvkey version / pubkey mismatch" do
 MoneyTree::Node.from_bip32 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH"
end

it "recognizes zero depth with non-zero parent fingerprint" do
 MoneyTree::Node.from_bip32 "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv"
end

it "recognizes zero depth with non-zero parent fingerprint" do
 MoneyTree::Node.from_bip32 "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ"
end

it "recognizes zero depth with non-zero index" do
 MoneyTree::Node.from_bip32 "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN"
end

it "recognizes zero depth with non-zero index" do
 MoneyTree::Node.from_bip32 "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8"
end

it "recognizes unknown extended key version" do
 MoneyTree::Node.from_bip32 "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4"
end

it "recognizes unknown extended key version" do
 MoneyTree::Node.from_bip32 "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9"
end

it "recognizes private key 0 not in 1..n-1" do
 MoneyTree::Node.from_bip32 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx"
end

it "recognizes private key n not in 1..n-1" do
 MoneyTree::Node.from_bip32 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G"
end

ref https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-5

Private Key import fails with OpenSSL 3.0

Error message when trying to import a private key using OpenSSL 3.0.5:

MoneyTree::Master.from_bip32(private)

results in this exception:

Exception: OpenSSL::PKey::PKeyError: pkeys are immutable on OpenSSL 3.0
--
 0: /Users/username/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/money-tree-5d80ffb7302b/lib/money-tree/key.rb:58:in `private_key='
 1: /Users/username/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/money-tree-5d80ffb7302b/lib/money-tree/key.rb:58:in `import'
 2: /Users/username/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/money-tree-5d80ffb7302b/lib/money-tree/key.rb:46:in `initialize'
 3: /Users/username/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/money-tree-5d80ffb7302b/lib/money-tree/node.rb:36:in `new'
 4: /Users/username/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/money-tree-5d80ffb7302b/lib/money-tree/node.rb:36:in `parse_out_key'
 5: /Users/username/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/money-tree-5d80ffb7302b/lib/money-tree/node.rb:31:in `from_bip32'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.