How Key Becomes Bitcoin Address: Mainnet and Testnet Variations

Understanding Mainnet and Testnet Bitcoin Addresses

Abhishek Chauhan
Coinmonks
Published in
3 min readDec 18, 2023

--

Journey from Key to Bitcoin Address

A Bitcoin address serves a similar role to that of an email address — it’s where funds are sent and received. Unlike traditional email addresses, however, Bitcoin addresses are not arbitrarily chosen; they are the product of a public key through a unique cryptographic transformation. This intricate process ensures the utmost security and privacy for Bitcoin transactions.

Why Convert a Public Key to a Bitcoin Address?

The transition from a public key to a Bitcoin address isn’t arbitrary — it’s a cornerstone of Bitcoin’s security and privacy principles:

  • Enhanced Security: Utilizing hash functions that are one-way operations, it becomes virtually impossible to deduce the public key — and by extension, the private key — from a Bitcoin address.
  • Improved Privacy: Possessing someone’s Bitcoin address alone isn’t enough to unveil their public key or their transaction history, preserving the user’s anonymity.

The Conversion Process Explained

The journey of converting a public key into a Bitcoin address unfolds through a series of precise cryptographic steps:

  1. SHA-256 Hashing: Initiates with hashing the public key using the SHA-256 algorithm, ensuring robust encryption.
  2. RIPEMD-160 Hashing: The output from SHA-256 undergoes further hashing via the RIPEMD-160 algorithm, optimizing the address’s size.
  3. Network Version Byte: This byte differs between mainnet (0x00) and testnet (0x6f).
  4. Checksum: To prevent errors, a checksum is generated by double-hashing the versioned output with SHA-256 and appending the first four bytes
  5. Base58Check Encoding: The concatenation of the version byte, hash, and checksum is encoded using Base58Check, culminating in the sequence of characters known as a Bitcoin address.

Dive Into the Code

Below is a Node.js script that encapsulates the conversion process. Each function is annotated for clarity:

// Importing the crypto module for cryptographic functions
const crypto = require('crypto');
// Importing the bs58check module for Base58Check encoding
const bs58check = require('bs58check');

/**
* Generates a public key using elliptic curve cryptography (ECC).
* ECC uses smaller keys compared to non-ECC cryptography to provide equivalent security.
*/
const generatePublicKey = () => {
// Generating a key pair using Bitcoin's secp256k1 elliptic curve.
const { privateKey } = crypto.generateKeyPairSync('ec', {
namedCurve: 'secp256k1', // Using secp256k1 curve.
publicKeyEncoding: { type: 'spki', format: 'der' }, // Encoding the public key in DER format.
privateKeyEncoding: { type: 'pkcs8', format: 'der' } // Encoding the private key in DER format.
});

// Deriving the public key from the private key.
const publicKey = crypto.createPublicKey({ key: privateKey, format: 'der', type: 'pkcs8' });
// Exporting the public key in DER format.
return publicKey.export({ type: 'spki', format: 'der' });
};

/**
* Hashes the public key first with SHA-256 and then with RIPEMD-160 to create a public key hash.
* This two-step hashing process is used for additional security.
*/
const hashPublicKey = (publicKey) => {
// Hashing the public key using SHA-256.
const sha256Hash = crypto.createHash('sha256').update(publicKey).digest();
// Hashing the SHA-256 output using RIPEMD-160.
return crypto.createHash('ripemd160').update(sha256Hash).digest();
};

/**
* Creates a Bitcoin address from the hashed public key.
* The function supports different network bytes for mainnet and testnet addresses.
*/
const createBitcoinAddress = (hashedPublicKey, networkByte = 0x00) => {
// Creating a buffer for the network version byte (0x00 for mainnet, 0x6f for testnet).
const versionBuffer = Buffer.alloc(1, networkByte);
// Concatenating the version byte with the hashed public key.
const payload = Buffer.concat([versionBuffer, hashedPublicKey]);
// Encoding the payload using Base58Check.
return bs58check.encode(payload);
};

// Generating the public key.
const publicKey = generatePublicKey();

// Hashing the public key.
const hashedPublicKey = hashPublicKey(publicKey);

// Creating a Bitcoin address for mainnet.
const bitcoinAddressMainnet = createBitcoinAddress(hashedPublicKey, 0x00);
// Creating a Bitcoin address for testnet.
const bitcoinAddressTestnet = createBitcoinAddress(hashedPublicKey, 0x6f);

// Logging the generated addresses to the console.
console.log(`Generated Bitcoin Address (Mainnet): ${bitcoinAddressMainnet}`);
console.log(`Generated Bitcoin Address (Testnet): ${bitcoinAddressTestnet}`);

Conclusion

The cryptographic journey from a public key to a Bitcoin address is a testament to the security-focused architecture of Bitcoin. By understanding this process and implementing the provided Node.js code, developers and enthusiasts alike can further their grasp on the intricate workings of Bitcoin addresses.

--

--

Coinmonks
Coinmonks

Published in Coinmonks

Coinmonks is a non-profit Crypto Educational Publication. Other Project — https://coincodecap.com/ & Email — gaurav@coincodecap.com

Abhishek Chauhan
Abhishek Chauhan

Written by Abhishek Chauhan

👨‍💻 Blockchain dev sharing insights on innovative solutions. Follow me on LinkedIn: https://www.linkedin.com/in/ac12644 🤝 GitHub: https://github.com/ac12644

Responses (1)