Public Key Cryptography
Understanding public-private key pairs and their use in blockchain addresses.
Intermediate⏱️ 40 min📚 Prerequisites: 1
Public Key Cryptography
Public key cryptography (asymmetric cryptography) uses two keys: a public key (shared) and a private key (secret).
Key Concepts
- Private Key: Secret, never shared, used to sign transactions
- Public Key: Shared publicly, used to verify signatures
- Address: Derived from public key, used to receive funds
Key Pair Generation
RUSTstruct KeyPair { private_key: String, public_key: String, address: String, // Derived from public key } fn generate_keypair() -> KeyPair { // In production: use cryptographic library // let (private, public) = generate_ecdsa_keypair(); KeyPair { private_key: String::from("private_key_..."), public_key: String::from("public_key_..."), address: String::from("address_..."), } }
Address Generation
Blockchain addresses are typically derived from public keys:
- Hash the public key (SHA-256 or similar)
- Take a portion of the hash
- Encode it (Base58, hex, etc.)
RUSTfn derive_address(public_key: &str) -> String { // Hash public key // let hash = sha256(public_key); // Take first 20 bytes for Ethereum-style address // Encode as hex format!("0x{}", &public_key[..20]) }
Wallet Structure
RUSTstruct Wallet { keypair: KeyPair, balance: u64, } impl Wallet { fn new() -> Self { Wallet { keypair: generate_keypair(), balance: 0, } } fn address(&self) -> &str { &self.keypair.address } }
Security Principles
- Never share private key: Anyone with it can spend your funds
- Public key is safe: Can be shared freely
- Address is public: Used to receive funds
- Backup private key: Loss = permanent fund loss
Use in Blockchain
- Bitcoin: Public key → SHA-256 + RIPEMD-160 → Base58 address
- Ethereum: Public key → Keccak-256 → Last 20 bytes → Hex address
- Key derivation: HD wallets use BIP32/BIP44
Code Examples
Key Pair Structure
Creating and using key pairs
RUST
struct KeyPair {
private_key: String,
public_key: String,
address: String,
}
fn generate_keypair() -> KeyPair {
let private_key = "private_key_abc123";
let public_key = "public_key_xyz789";
KeyPair {
private_key: String::from(private_key),
public_key: String::from(public_key),
address: derive_address(public_key),
}
}
fn derive_address(public_key: &str) -> String {
format!("0x{}", &public_key[..20.min(public_key.len())])
}
fn main() {
let keypair = generate_keypair();
println!("Public Key: {}", keypair.public_key);
println!("Address: {}", keypair.address);
}Explanation:
Key pairs are the foundation of blockchain security. The private key must be kept secret, while the public key and address can be shared.
Wallet Implementation
Creating a wallet with key pair
RUST
struct KeyPair {
private_key: String,
public_key: String,
address: String,
}
struct Wallet {
keypair: KeyPair,
balance: u64,
}
impl Wallet {
fn new() -> Self {
let keypair = KeyPair {
private_key: String::from("secret_key"),
public_key: String::from("public_key_12345678901234567890"),
address: String::from("0x12345678901234567890"),
};
Wallet {
keypair,
balance: 0,
}
}
fn address(&self) -> &str {
&self.keypair.address
}
fn get_balance(&self) -> u64 {
self.balance
}
}
fn main() {
let wallet = Wallet::new();
println!("Wallet address: {}", wallet.address());
println!("Balance: {}", wallet.get_balance());
}Explanation:
A wallet contains a key pair and tracks balance. The address is used to receive funds, and the private key is used to authorize spending.
Exercises
Create Wallet
Create a wallet with a key pair and display its address!
Starter Code:
RUST
struct KeyPair {
private_key: String,
public_key: String,
address: String,
}
struct Wallet {
keypair: KeyPair,
}
fn main() {
let wallet = Wallet::new();
println!("Address: {}", wallet.address());
}