Demystifying Bitcoin Addresses the Right Way

Photo by Andrew Neel on Unsplash

Demystifying Bitcoin Addresses the Right Way

One of the fundamental ideas behind Bitcoin is to serve as a peer-to-peer network for exchanging value. In order to exchange these values, we have to find a means to collect this Bitcoin value without necessarily exposing the receiver of the Bitcoin.

The Bitcoin network uses addresses to facilitate the collection of Bitcoin between two parties without exposing the sender and receiver.

Bitcoin places a strong emphasis on privacy, which is why generating a new address for every transaction you want to make is very important.

In this article, I am going to explain the different types of Bitcoin addresses and how to generate one

A Bitcoin address is a string of alphanumeric characters that functions as a destination for Bitcoin transactions. It operates similarly to an email address, enabling users to send and receive bitcoins on the decentralized blockchain network.

However, unlike traditional email addresses, Bitcoin addresses are more secure and utilize cryptographic principles to enhance privacy.

Public key cryptography is employed to generate a key pair that governs access to bitcoins. This key pair comprises a private key and a public key derived from the private key.

The public key via generated address is used to receive bitcoin, and the private key is used to sign transactions that spend the bitcoin.

A private key can be converted into a public key, but a public key cannot be converted back into a private key because the math only works one way.

Private Key

Private key is a number pick at random, in order to ensure this key is secure the source randomness has to be secured, Bitcoin software uses cryptographically secure random number generators to produce 256 bits of entropy.

the private key can be any number between 0 and n - 1 inclusive, where n is a constant (n = 1.1578 × 1077, slightly less than 2256) defined as the order of the elliptic curve used in Bitcoin

Read More about Private key here

Public keys

They public keys are generated from the private, a strong process is needed such that the public key cannot be use to recover the private

In bitcoin , we use elliptic curve multiplication the generate the public key from the private key which is irreversible by system of today.

K = k × G, where k is the private key, G is a constant point called the generator point, and K is the resulting public key.

With a private key , we can multiple it with a predetermined point on the curve called the generator point G to produce another point somewhere else on the curve, which is the corresponding public key K. The generator point is specified as part of the secp256k1 standard and is always the same for all keys in bitcoin:

K = k × G

K is our public key k is the private key G is generator point G to produce another point somewhere else on the curve,

With elliptic curve multiplication, it is possible to get the public key from the private (one way) but impossible to go in reverse direction to get the private key from the public key, thus the math only works in one direction

Pay to Public Key Hash Address (P2PKH - Legacy)

P2PKH address in bitcoin start with 1 which represent the legacy format of address while the introduction of Segregated Witness (SegWit), newer address formats start with "3" or "bc1" have become more common which offer improved scalability and reduced transaction fees.

In P2PKH, bitcoin value is send to the hash of recipient public key, The recipient's public key is hashed using a cryptographic hash function, usually SHA-256 followed by RIPEMD-160, resulting in a shorter and fixed-length hash known as the public key hash (PKH).


const bitcoin = require('bitcoinjs-lib')
const ECPairFactory = require('ecpair').default
const ecc = require('tiny-secp256k1')
const fs = require('fs');

const EcPair = ECPairFactory(ecc)

const network = bitcoin.networks.testnet

async function createP2PKHAddress() {
  try {
    const keyPair = EcPair.makeRandom({ network: network})
    // P2WPKH -> payments.p2wpkh

    console.log('keyPair.publicKey', keyPair.publicKey)
    const { address } = bitcoin.payments.p2pkh({
      pubkey: keyPair.publicKey,
      network: network
    })
    console.log('address', address)

    const privateKey = keyPair.toWIF()
    console.log('Private Key', privateKey)

    const wallet = {
      address: address,
      privateKey: privateKey
    }
    console.log('wallet', wallet)

  } catch (error) {
    console.log(error)
  }
}

createP2PKHAddress()

Pay to Script Hash (P2SH)

P2SH is a Bitcoin address format that allows the spending of bitcoins secured by a script without exposing the script directly in the spending transaction

Instead of revealing the script in the output scriptPubKey (locking script), a P2SH address includes a hash of the script. The actual script is only revealed when the funds are spent. This adds a layer of privacy and flexibility.

pay-to-script-hash addresses are not the hash of the public key, but of a script that involves certain spending conditions, which stay hidden from the sender

P2SH addresses are commonly used for multi-sig addresses, which can specify that signatures from several keys are required to authorize the transaction.


const bitcoin = require('bitcoinjs-lib')
const ECPairFactory = require('ecpair').default
const ecc = require('tiny-secp256k1')
const fs = require('fs');

const EcPair = ECPairFactory(ecc)

const network = bitcoin.networks.testnet

async function createP2SHAddress() {
  try {
    const keyPair = EcPair.makeRandom({ network: network})

    console.log('keyPair.publicKey', keyPair.publicKey)

    // P2WPKH -> payments.p2wpkh

    const { address } = bitcoin.payments.p2sh({
      pubkey: keyPair.publicKey,
      network: network
    })
    console.log('address', address)

    const privateKey = keyPair.toWIF()
    console.log('Private Key', privateKey)

    const wallet = {
      address: address,
      privateKey: privateKey
    }
    console.log('wallet', wallet)

  } catch (error) {
    console.log(error)
  }
}

createP2SHAddress()

SegWit Addresses (P2WPKH)

SegWit addresses, known as Pay-To-Witness-Public-Key-Hash (P2WPKH) addresses, are easily identifiable as they commence with ‘bc1q’. Many also recognize them by another name: Bech32 addresses.

The standout feature of P2WPKH is its capability to trim down the block size. This streamlining effect has tangible benefits: it cuts transaction fees and boosts the speed of transactions. For many, this cost-effective nature has cemented its status as the go-to Bitcoin address The public key hash in P2WPKH is 20 bytes.

The script hash in P2WSH is 32 bytes.

Code example on how to generate one


const bitcoin = require('bitcoinjs-lib')
const ECPairFactory = require('ecpair').default
const ecc = require('tiny-secp256k1')
const fs = require('fs');

const EcPair = ECPairFactory(ecc)

const network = bitcoin.networks.testnet

async function createAP2WPKHAddress() {
  try {
    const keyPair = EcPair.makeRandom({ network: network})

    console.log('keyPair.publicKey', keyPair.publicKey)

    // P2WPKH -> payments.p2wpkh

    const { address } = bitcoin.payments.p2wpkh({
      pubkey: keyPair.publicKey,
      network: network
    })
    console.log('address', address)

    const privateKey = keyPair.toWIF()
    console.log('Private Key', privateKey)

    const wallet = {
      address: address,
      privateKey: privateKey
    }
    console.log('wallet', wallet)

  } catch (error) {
    console.log(error)
  }
}

createAP2WPKHAddress()

P2WSH (Pay to Witness Script Hash)

P2WSH was introduced as part of the Segregated Witness (SegWit) upgrade to the Bitcoin protocol. SegWit was activated in August 2017 and brought several improvements, including increased block size and a fix for transaction malleability. P2WSH is one of the new transaction types enabled by SegWit

This is a Bitcoin script construction where funds are locked to a script hash. The spending conditions are defined by a witness script, and to spend the funds, the spender must provide the witness data that satisfies the conditions of this script.

The script hash in P2WSH is 32 bytes.

Code example on how to generate one

// createWalletWithP2WSH

const bitcoin = require('bitcoinjs-lib')
const ECPairFactory = require('ecpair').default
const ecc = require('tiny-secp256k1')
const fs = require('fs');

const EcPair = ECPairFactory(ecc)

const network = bitcoin.networks.testnet

async function createP2WSHAddress() {
  try {
    const keyPair = EcPair.makeRandom({ network: network})

    console.log('keyPair.publicKey', keyPair.publicKey)

    // P2WPKH -> payments.p2wpkh

    const { address } = bitcoin.payments.p2wsh({
      pubkey: keyPair.publicKey,
      network: network
    })
    console.log('address', address)

    const privateKey = keyPair.toWIF()
    console.log('Private Key', privateKey)

    const wallet = {
      address: address,
      privateKey: privateKey
    }
    console.log('wallet', wallet)


  } catch (error) {
    console.log(error)
  }
}

createP2WSHAddress()

P2TR (Pay-to-Taproot)

Pay-to-Taproot (P2TR) represents a ScriptPubKey category that secures bitcoin to a script. This script is designed to be unlocked either by a public key or a Merkelized Alternative Script Tree (MAST).

At a glance, a P2TR output secures bitcoin to a lone Schnorr public key, referred to as Q. Yet, this Q is, in reality, the combination of a public key P and another public key M. The derivation of M involves calculating it from the Merkle root of a collection of other ScriptPubKeys

Code example on how to generate one

const bitcoin = require('bitcoinjs-lib')
const ECPairFactory = require('ecpair').default
const ecc = require('tiny-secp256k1')
const fs = require('fs');

const EcPair = ECPairFactory(ecc)

const network = bitcoin.networks.testnet

async function createP2TRAddress() {
  try {
    const keyPair = EcPair.makeRandom({ network: network})

    console.log('keyPair.publicKey', keyPair.publicKey)

    // P2WPKH -> payments.p2wpkh

    const { address } = bitcoin.payments.p2tr({
      pubkey: keyPair.publicKey,
      network: network
    })
    console.log('address', address)

    const privateKey = keyPair.toWIF()
    console.log('Private Key', privateKey)

    const wallet = {
      address: address,
      privateKey: privateKey
    }
    console.log('wallet', wallet)

  } catch (error) {
    console.log(error)
  }
}

createWalletP2TR()

Conclusion

In conclusion, understanding the intricacies of Bitcoin addresses is crucial for users seeking to navigate the world of bitcoin transactions securely and privately. Bitcoin, with its emphasis on peer-to-peer value exchange, employs a robust system of cryptographic principles to safeguard user privacy

Reference

https://sadeeqcode.medium.com/why-bitcoin-address-is-not-like-an-account-number-e5a5261a0605

https://river.com/learn/terms/p/pay-to-taproot-p2tr/

https://bitcoin.design/guide/glossary/address/

https://github.com/bitcoinjs/bitcoinjs-lib

https://www.oreilly.com/library/view/mastering-bitcoin-3rd/9781098150082/

https://developer.bitcoin.org/glossary.html#term-P2PKH-address