"Not your keys, not your coins."—Unknown Author, 21st Century
The Avalanche project, and specifically their Core App, blur the lines between Bitcoin and Ethereum networks. This brilliant concept has been around for some time, but I've only recently discovered it for myself. Thus, I decided to dive into Avalanche and install Core App.
When using a non-custodial wallet, I want to be certain I truly own my addresses. I need assurance that, should the wallet ever disappear, I can manually generate the private key from the seed phrase and continue managing my funds.
It's unlikely that Core App will vanish without a trace. However, imagine a scenario where a Chrome update glitch disables extensions, and you need to make a transaction immediately. It's a stretch, but such thought experiments help us understand whether we truly own our coins or are dependent on intermediaries.
notice want swift foam name congress visit coin census zebra prepare hard
We'll use this seed phrase as an experiment. I encourage you to follow along. Entering this seed into Core App reveals the following addresses for the Avalanche (C-Chain) and Bitcoin networks:
Avalanche: 0xe2d6A42472D480dF98A4A5CAcD525488624d81f9
Bitcoin: bc1qz8vm59vv0k5f3rxrqavcmenwtf3cjnv0c7nqyd
Since Avalanche operates as an L2 network on Ethereum, the C-Chain address is an Ethereum address. Using the same seed phrase for MetaMask and Core App, we expect to see identical addresses for Ethereum and Avalanche. Let's extract the private key for our Avalanche address.
If you've dealt with manual key and address derivation, you're likely familiar with Ian Coleman's Mnemonic Code Converter, a versatile key and address calculator supporting many cryptocurrencies and standards.
Insert our seed phrase in the BIP39 Mnemonic
field (near the top). Below, in the Coin
field, select "ETH - Ethereum". Scroll to Derived Addresses
and there's our Avalanche address, alongside its private key:
0x029df9bf2fe731dcca0321bf705b7737d0f022fc57565310ae34ada05ad54e1d
Great! Now, switch the Coin
field to "BTC - Bitcoin". The addresses start with a one, whereas our Bitcoin address starts with bc1
(in Bitcoin terminology, this is a bech32 address format). To generate bech32 addresses, we need to adjust the Derivation Path
to "BIP84". Let's do that.
Here's the first Bitcoin address:
bc1qxazf7vs74lkadd00nztdgykcwhhcyue6pjsxds
Guess what? It's not our Core App address. Our address doesn't appear on this list at all.
Actually, there's no need to panic. You're reading this article, which will show you how to obtain the private key for your Bitcoin address from Core App.
The good news is you've already seen the private key for our Bitcoin address. It's the same as for our Avalanche address, but Ethereum keys are traditionally in HEX format, and Bitcoin keys in WIF (Wallet Import Format). Converting between these formats is trivial.
Yes, Core App uses a single private key for all addresses. This deviates from the standard key derivation and bech32 address generation methods. That's why we can't generate the WIF and address using tools like the Mnemonic Code Converter. But it's not a flaw; it's just a unique approach by Core App to Bitcoin address generation.
So, we want to ensure the Bitcoin address from Core App with our seed phrase truly belongs to us. We'll generate:
- The private key in WIF format;
- The address, to verify it matches the one in Core App.
We'll need to write and execute some code. You don't have to do this with me; you can take my word for it. Since Core App is unlikely to disappear, this practical exercise is not about solving an immediate problem. It's about peace of mind, knowing there's a solution if needed.
If you're like me and want to experience this firsthand, you'll need to install Node.js.
Create a directory, open a console there, and install the necessary libraries for elliptic cryptography.
npm i ecpair tiny-secp256k1 bitcoinjs-lib
These library versions are current as of this article's writing. If you're from the future, please consider that these were the versions used (in the package.json
file):
{
"type": "module",
"dependencies": {
"bitcoinjs-lib": "^6.1.5",
"ecpair": "^2.1.0",
"tiny-secp256k1": "^2.2.3"
}
}
The following JavaScript code (in a file named index.js
) will achieve our goals:
import bitcoin from 'bitcoinjs-lib'
import { ECPairFactory } from 'ecpair'
import * as tinysecp from 'tiny-secp256k1'
// Our Avalanche address's private key without the "0x" prefix
const privateKeyHex =
'029df9bf2fe731dcca0321bf705b7737d0f022fc57565310ae34ada05ad54e1d'
const keyPair =
ECPairFactory(tinysecp).fromPrivateKey(Buffer.from(privateKeyHex, 'hex'))
// Print the private key in WIF format to the console
console.log(keyPair.toWIF())
const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey })
// Print the address to the console
console.log(address)
Running this code (node .
) produces the following console output:
KwJoFHUnDThk5xEnifGFdAKsPnoSRKS6GjqskTx1X5Eco5eegiUa
bc1qz8vm59vv0k5f3rxrqavcmenwtf3cjnv0c7nqyd
The top line is our sought-after private key. The bottom line is the Bitcoin address. And it matches the address we see in Core App.
Remember, with great power comes great responsibility. Don't generate your private key just anywhere, and certainly don't store it openly. It's risky.
Core App generates a secure Bitcoin address, and this address indeed belongs to whoever knows the seed phrase. Memorize your seed phrase and sleep soundly.
Your keys, your coins.