Digital Signatures
Implementing digital signatures for transaction authorization in blockchain.
Intermediate⏱️ 45 min📚 Prerequisites: 1
Digital Signatures
Digital signatures prove that a transaction was authorized by the owner of the private key, without revealing the key itself.
How Digital Signatures Work
- Signing: Use private key to sign transaction data
- Verification: Use public key to verify signature is valid
- Non-repudiation: Signer cannot deny signing
- Integrity: Any change to data invalidates signature
Signature Process
RUST// Simplified signature structure struct Signature { r: String, // Signature component 1 s: String, // Signature component 2 } struct Transaction { from: String, to: String, amount: u64, signature: Option<Signature>, }
Signing a Transaction
RUSTfn sign_transaction(tx: &mut Transaction, private_key: &str) { let data = format!("{}{}{}", tx.from, tx.to, tx.amount); // In production: use cryptographic library // let signature = sign_with_private_key(&data, private_key); tx.signature = Some(Signature { r: format!("sig_r_{}", data), s: format!("sig_s_{}", data), }); }
Verifying a Signature
RUSTfn verify_signature(tx: &Transaction, public_key: &str) -> bool { if tx.signature.is_none() { return false; } let data = format!("{}{}{}", tx.from, tx.to, tx.amount); // In production: verify with public key // verify_with_public_key(&data, &tx.signature, public_key) true // Simplified }
Use Cases in Blockchain
- Transaction authorization: Prove you own the funds
- Smart contract calls: Authorize contract execution
- Block validation: Validators sign blocks
- Identity verification: Prove ownership of address
ECDSA (Elliptic Curve Digital Signature Algorithm)
Most blockchains use ECDSA:
- Bitcoin: secp256k1 curve
- Ethereum: secp256k1 curve
- Fast and secure
- Small signature size
Code Examples
Signature Structure
Basic digital signature structure
RUST
struct Signature {
r: String,
s: String,
}
struct Transaction {
from: String,
to: String,
amount: u64,
signature: Option<Signature>,
}
impl Transaction {
fn sign(&mut self, private_key: &str) {
let data = format!("{}{}{}", self.from, self.to, self.amount);
self.signature = Some(Signature {
r: format!("r_{}", data),
s: format!("s_{}", data),
});
}
fn is_signed(&self) -> bool {
self.signature.is_some()
}
}
fn main() {
let mut tx = Transaction {
from: String::from("Alice"),
to: String::from("Bob"),
amount: 100,
signature: None,
};
println!("Signed: {}", tx.is_signed());
tx.sign("private_key_123");
println!("Signed: {}", tx.is_signed());
}Explanation:
Digital signatures prove transaction authorization. The signature is created using the sender's private key and can be verified with their public key.
Signature Verification
Verifying transaction signatures
RUST
struct Signature {
r: String,
s: String,
}
struct Transaction {
from: String,
to: String,
amount: u64,
signature: Option<Signature>,
}
fn verify_transaction(tx: &Transaction, public_key: &str) -> bool {
if tx.signature.is_none() {
return false;
}
let data = format!("{}{}{}", tx.from, tx.to, tx.amount);
let sig = tx.signature.as_ref().unwrap();
sig.r.starts_with("r_") && sig.s.starts_with("s_")
}
fn main() {
let tx = Transaction {
from: String::from("Alice"),
to: String::from("Bob"),
amount: 100,
signature: Some(Signature {
r: String::from("r_AliceBob100"),
s: String::from("s_AliceBob100"),
}),
};
let valid = verify_transaction(&tx, "alice_public_key");
println!("Transaction valid: {}", valid);
}Explanation:
Signature verification ensures the transaction was signed by the owner of the private key corresponding to the public key. This prevents unauthorized transactions.
Exercises
Sign and Verify
Create a transaction, sign it, and verify the signature!
Starter Code:
RUST
struct Signature {
r: String,
s: String,
}
struct Transaction {
from: String,
to: String,
amount: u64,
signature: Option<Signature>,
}
fn main() {
let mut tx = Transaction {
from: String::from("Alice"),
to: String::from("Bob"),
amount: 50,
signature: None,
};
}