Things are moving fast at BITBOX. Since launching 8 weeks ago it’s been downloaded over 10,000 times from 48 countries.

map

Things have really started to pick up this week where 2 days ago it had over 2600 downloads from 9 countries.

spike

If you’ve taken time to download BITBOX or you’ve sent a $BCH donation I want to express my gratitude. This is an amazing community and I look forward to all the great stuff we’re going to accomplish in the coming years.

If you’re building something w/ BITBOX or if you just want to connect there is a slack channel. Contact me on twitter and I’ll send you an invite. I want to do everything I can to help on-ramp developers to BITBOX.

Today I’m releasing bitbox-cli v0.6.0 w/ a completely refactored Crypto class and a bunch of additions to an already powerful HDNode class.

Crypto

Buffers instead of hex

It came to my attention that hashing a hex encoded string produces a different digest than hashing the same data encoded as a Buffer. That’s because when hashing a hex encoded string each character is interpreted as it’s ASCII value.

This led to an initial refactoring of Crypto in which each method continued accepting hex input but internally parsed it in to a Buffer. But that felt too magical. Then I had two methods for each hash type, one for passing in hex and one for passing in a buffer. However that was too verbose.

So after a couple rounds of API churn I decided to just have all the methods in Crypto only accept and return buffers. This removes an entire class of bugs related to people incorrectly passing ASCII values.

Simpler names

It’s also became clear the method names were far too many characters. I simplified the naming to be more terse and obvious.

Methods

sha256

Utility for creating sha256 hash digests of data

// buffer from hex
let buffer = Buffer.from('0101010101010101', 'hex')
// sha256 hash the data
BITBOX.Crypto.sha256(buffer)
// <Buffer 04 ab c8 82 1a 06 e5 a3 09 37 96 7d 11 ad 10 22 1c b5 ac 3b 52 73 e4 34 f1 28 4e e8 71 29 a0 61>

sha256 more info

ripemd160

Utility for creating ripemd160 hash digests of data

// buffer from hex
let buffer = Buffer.from('0101010101010101', 'hex')
// ripemd160 hash the data
BITBOX.Crypto.ripemd160(buffer)
// <Buffer 58 25 70 1b 4b 97 67 fd 35 06 3b 28 6d ca 35 82 85 3e 06 30>

ripemd160 more info

hash256

Utility for creating double sha256 hash digests of data

// buffer from hex
let buffer = Buffer.from('0101010101010101', 'hex')
// hash256 hash the data
BITBOX.Crypto.hash256(buffer)
// <Buffer 72 83 38 d9 9f 35 61 75 c4 94 5e f5 cc cf a6 1b 7b 56 14 3c bb f4 26 dd d0 e0 fc 7c fe 8c 3c 23>

hash256 more info

hash160

Utility for creating ripemd160(sha256()) hash digests of data

// buffer from hex
let buffer = Buffer.from('0101010101010101', 'hex')
// hash160 hash the data
BITBOX.Crypto.hash160(buffer)
// <Buffer ab af 11 19 f8 3e 38 42 10 fe 8e 22 2e ac 76 e2 f0 da 39 dc>

hash160 more info

randomBytes

Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate.

BITBOX.Crypto.randomBytes(32)
// <Buffer d7 6e e8 f2 34 bd 4a 42 27 72 14 34 13 27 85 c2 9e 54 42 68 63 9c eb 7e a3 a8 68 e8 35 33 f7 a0>

randomBytes more info

HDNode

Methods

isPublic

Check if an HDNode can only derive public keys and children

isPublic more info

// mainnet xpub
let xpub = 'xpub6DWfGUo4cjC8oWmgZdpyFMH6v3oeyADfdUPhsehzn5jX44zpazivha3JxUtkcCvBEB1c6DGaiUmpyz2m1DRfGDEVZ5VxLLW2UNEbZ5iTRvi';
let node = BITBOX.HDNode.fromXPub(xpub);
BITBOX.HDNode.isPublic(node);
// true

// testnet xpriv
let xpriv = 'tprv8ggxJ8SG5EdqakzVUeLa9Gr7sqCdEcJPUNDmtdJscNxfmxoXvU36ZguiUWukJVEWEixAUr8pJabJkCt33wzxFQA587gqN51Lxdxx97zAzuG';
let node = BITBOX.HDNode.fromXPriv(xpriv);
BITBOX.HDNode.isPublic(node);
// false

isPrivate

Check if an HDNode can derive both public and private keys and children

// mainnet xpriv
let xpriv = 'xprv9ys4cvcoU8RoxqkZ7Fgt33te4LPHgcsKwyoZYVorkzp9uonWxWgP9wiSQhPeBUqVHbdAyov4Yi55RywBkDfZKdJFRqA51Anz6v72zGaMGZp';
let node = BITBOX.HDNode.fromXPriv(xpriv);
BITBOX.HDNode.isPrivate(node);
// true

// testnet xpub
let xpub = 'tpubDCxmZ3qLVVphg6NpsnAjQFqDPwr9HYqSgoAcUYAfqSgo32dL6NA8QXqWsS6XTjoGggohZKvujsAv2F2ugej9qfUYau2jSUB4JaYnfMsx3MJ';
let node = BITBOX.HDNode.fromXPub(xpub);
BITBOX.HDNode.isPrivate(node);
// false

isPrivate more info

toIdentifier

hash160 of Node’s public key. The same value you would see in a scriptPubKey.

// mainnet
let xpub = 'xpub6DWfGUo4cjC8oWmgZdpyFMH6v3oeyADfdUPhsehzn5jX44zpazivha3JxUtkcCvBEB1c6DGaiUmpyz2m1DRfGDEVZ5VxLLW2UNEbZ5iTRvi';
let node = BITBOX.HDNode.fromXPub(xpub);
let identifier = BITBOX.HDNode.toIdentifier(node);
// <Buffer cd d4 84 1d 2e 96 bf bf f7 9c d1 f4 a6 75 22 1c 7f 67 88 9c>
// the same as if we hash160ed it's publicKey
let publicKeyBuffer = BITBOX.HDNode.toPublicKey(node);
let hash160 = BITBOX.Crypto.hash160(publicKeyBuffer);
// <Buffer cd d4 84 1d 2e 96 bf bf f7 9c d1 f4 a6 75 22 1c 7f 67 88 9c>

toIdentifier more info