Source: https://twitter.com/aantonop/status/603701870482300928
Disclaimer: The methods discussed in this article are not recommended for short or long term storage of your Bitcoin. This is only for fun. Anything you do with this knowledge or the provided library is at your own risk. As long as you understand that, let’s begin.
Back in May of 2015 Andreas Antonopoulos posted the above picture that utilized steganography to embed a signed transaction into the image. This idea of concealing and easily decoding arbitrary data in other data intrigued me.
So I started thinking, how can we play with this idea? Can we use the file to store our Bitcoin private key? Heck, why not use the file itself as our seed for generating a mnemonic phrase? With this, I coded up a quick proof-of-concept here and uploaded a simple demo here.
Take the image from Andreas’ tweet and turn it into the following Bitcoin address, “bc1q57euh23y3qs2f9d5mtwpax5lqecfvrdkqce82a”.
Turning an image into a Bitcoin address effectively allows us to turn any seemingly arbitrary file into an inconspicuous, mobile unit of wealth. Now, instead of writing down a series of 12–24 words to recover and access funds all we need to do is carry around a photo on a thumb or hard drive.
We can even add a passphrase to prevent malicious actors from gaining access to our funds if they somehow attempt to brute-force our photo library.
/*
Bitimage Pseudocode
*/
//We'll need the following libraries
const Bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
const bip32 = require('bip32');
//Grab the kitten photo
kittenphoto.jpg;
//Get Data URI of kittenphoto.jpg
Data URI: data:[<media type>][;base64],<data>;
//Hash the base64 data of the kitten photo
const hash = Bitcoin.crypto.sha256(<data>);
//Use the hash to create a mnemonic phrase
const mnemonic = bip39.entropyToMnemonic(hash);
//Add a passphrase (Optional, but recommended)
const passphrase = ""
//Use the mnemonic and passphrase to generate the seed
const seed = bip39.mnemonicToSeed(mnemonic, passphrase);
//Use the seed to generate a bech32 address
const root = bip32.fromSeed(seed, network);
const keyPair = root.derivePath(`m/84'/0'/0'/0/0`);
const address = Bitcoin.payments.p2wpkh({pubkey: keyPair.publicKey}).address;
//Result
address === "bc1q57euh23y3qs2f9d5mtwpax5lqecfvrdkqce82a";
Every file can be broken down, defined and represented as a Base64 string. Bitimage extracts the Base64 string from the data URI of any file that you feed it and uses that string to generate a mnemonic phrase.
The Base64 string for the kitten image is rather long so I’ve shortened it for presentation purposes here,
“/9j/4AAQSkZJRg …. +MbzXZF3n/2Q==”.
Since the Base64 string is rather unwieldy we hash it using the SHA256 hash function leaving us with the following, “1808d35318ac7cb98b69ff9779b699d6a631f15e0b353ac89b7c4020774832ed”.
We then pass this hash off to BIP39’s “
entropyToMnemonic
” function to generate our mnemonic phrase. With the mnemonic phrase in hand we can generate our seed with or without a passphrase. Including a passphrase will prevent any random person with access to the file from accessing our funds, assuming the passphrase is sufficient and cannot be easily brute-forced.Using this seed we can now generate our keyPair and corresponding addresses/private keys for the uploaded file using the
bitcoinjs-lib
library. As expected, we are left with the following Bitcoin address, “bc1q57euh23y3qs2f9d5mtwpax5lqecfvrdkqce82a”.The mnemonic for the kitten photo without a passphrase contains roughly 0.00095133 BTC.
Feel free to claim it if you manage to sweep the keys in time.
As a challenge, I have also sent 0.01 BTC to the following address, “bc1qcyrndzgy036f6ax370g8zyvlw86ulawgt0246r”. This address was generated using the kitten image along with a BIP39 passphrase. If you manage to claim it, congrats!
Again, feel free to take a look at the demo site here or run it locally on your computer by cloning the repo on Github here.
In Part 2 we will discuss how to use the methods discussed here to timestamp our documents and prove their existence at a certain point in time without utilizing any centralized third party.
Have any questions? Feel free to reach out:
Github: https://github.com/coreyphillips
Twitter: @coreylphillips