Exploring Bitcoin with Rust code – Part 1

Bitcoin-Rust

Let’s get started with this ‘crate’ : bitcoin

*version = “0.31.0” at time of writing

The aim is to learn more Rust, and what better way to learn about cryptography than experimenting with Bitcoin ?

In addition we’ll look at serializing and printing bytes in hex and binary format.


Note: One of the crate's dependencies is secp256k1 a Rust "wrapper library" for Pieter Wuille's `libsecp256k1` which implements ECDSA and BIP 340 signatures for the SECG elliptic curve group secp256k1 and related utilities.

More about the Rust “Bitcoin” crate:


This is a library that supports the Bitcoin network protocol and associated primitives. It is designed for Rust programs built to work with the Bitcoin network.

Except for its dependency on libsecp256k1 (and optionally libbitcoinconsensus), this library is written entirely in Rust. It illustrates the benefits of strong type safety, including ownership and lifetime, for financial and/or cryptographic software.

Official Documentation

Webdock – Fast Cloud VPS Linux Hosting

Enough of the intro, let’s get our hands dirtier than SBF’s ex :

1. Create a new Rust binary project

cargo new bitcoin 
❯ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug

3 directories, 4 files

cargo add bitcoin
view Cargo.toml
[package]
name = "btc"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.8.5"
bitcoin = { version = "0.31.0", features = ["rand-std"] }
~                                                          

2. Edit ‘main.rs’

cd src
vim main.rs
# and remove the "hello world" shizz and add the code shown below:
#![allow(unused)]
use bitcoin::secp256k1::{rand, Secp256k1};
use bitcoin::PublicKey;
use bitcoin::{Address, Network};

/// The different types of addresses.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum AddressType {
    /// Pay to pubkey hash.
    P2pkh,
    /// Pay to script hash.
    P2sh,
    /// Pay to witness pubkey hash.
    P2wpkh,
    /// Pay to witness script hash.
    P2wsh,
    /// Pay to taproot.
    P2tr,
}

3. Add code for Creating Public / Private Key Pairs

Asymmetric cryptography is a branch of cryptography where a secret key can be divided into two parts, a public key and a private key.

The public key can be given to anyone, trusted or not, while the private key must be kept secret (just like the key in symmetric cryptography).

Let’s create some key pairs and view the respective public keys

fn main() {
    //// Generate random key pair.
    let s = Secp256k1::new();
    let (secret_key, public_key) = s.generate_keypair(&mut rand::thread_rng());

    println!("\n---\n");

    // Print the hexadecimal representation of the public key
    println!("Public Key:");
    for byte in public_key.serialize_uncompressed().iter() {
        print!("{:02x} ", byte);
    }
    // The {:02x} format specifier prints each byte as a two-digit hexadecimal number.
    println!("\n---\n");

    // Print the hexadecimal representation of the compressed public key
    println!("Compressed Public Key:");
    for byte in public_key.serialize().iter() {
        print!("{:02x} ", byte);
    }

    // print in binary!
    println!("\n---\n");
    println!("Binary representation of the Compressed Public Key:");
    for byte in public_key.serialize().iter() {
        print!("{:b} ", byte);
    }
}
  1. Secp256k1::new(): This line creates a new instance of the Secp256k1 object, which is a cryptographic library often used for handling operations related to the Bitcoin protocol.
  2. s.generate_keypair(&mut rand::thread_rng()): This line generates a random key pair (consisting of a secret key and a corresponding public key) using the generate_keypair function from the Secp256k1 instance (s). It utilizes a random number generator from the rand crate (rand::thread_rng()).
  3. The code then proceeds to print the public key in different representations:
    • public_key.serialize_uncompressed(): This section prints the public key in its uncompressed form in hexadecimal format using {:02x} format specifier.
    • public_key.serialize(): This part prints the public key in its compressed form in hexadecimal format.
    • Lastly, the code attempts to print the public key in binary format by using print!("{:b} ", byte) for each byte in the serialized public key.

Output

Video:

Screenshot:

output

Note we only ever want to display the public key in our output code (cos: security)