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

  1. Signing: Use private key to sign transaction data
  2. Verification: Use public key to verify signature is valid
  3. Non-repudiation: Signer cannot deny signing
  4. 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

RUST
fn 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

RUST
fn 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!

Medium

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,
    };
}