Skip to content

Latest commit

 

History

History
150 lines (102 loc) · 5.08 KB

02_digital_signatures.md

File metadata and controls

150 lines (102 loc) · 5.08 KB

Lecture 2: Digital Signatures

Blockchain heavily relies on the safety of data transmission. Digital signatures ensure that the information comes from the trusted source. This lectures introduces students to different types of signatures and methods of key derivation

Why signatures?

Like in real like we need to ensure that the entity sending a message or taking part in a transaction is authentic.

The only difference is that the digital signatures are represented not by ink, but by cryptographic proof.

Interface

We can represented the digital signatures with the following interface:

//sk - secret (private) key
//payload - data to be signed (usually bytes)
fn sign(sk, payload) -> signature;

//pk - public key of a sender
fn verify(pk, payload, signature) -> bool;

In a nutshell, what signatures are is just additional wrappers around cryptographic hash functions.

Example in Rust

use std::fmt::format;
use parity_scale_codec::{ Encode, Decode};
use sp_core::{H256, H512, Pair};
use sp_core::sr25519::{Signature};

fn main() {
	let print_string = generate("//Alice", Vote::Yes);
    println!("Alice - Yes - {}", fm(print_string));

	let print_string = generate("//Bob", Vote::No);
    println!("Bob - No - {}", fm(print_string));
	
}

#[derive(Clone, Eq, PartialEq, Encode, Decode)]
pub enum Vote {
	Yes,
	No
}

fn generate(key: &str, vote: Vote) -> String {
	let pair: sp_core::sr25519::Pair = Pair::from_string(key, None).unwrap();

	let payload = (vote, 10u32).encode();
	let payload = payload.as_slice().to_owned();
	let signed = pair.sign(&payload);

	format!("{:02x?}", signed.0)
}

fn verify(load: [u8; 64]) -> bool {
	let pair: sp_core::sr25519::Pair = Pair::from_string("//Bob", None).unwrap();
	let s = Signature::from_raw(load);
	let payload = (Vote::Yes, 10u32).encode();
	sp_core::sr25519::Pair::verify(&s, payload, &pair.public())
}

fn fm(s: String) -> String {
	let print_string = s.replace(", ", "");
	let print_string = print_string.replace('[', "");
	print_string.replace(']', "")
}

Source: SkymanOne's Gist

Replay attack

Replay attacks occur when someone intercepts and resends a valid message. The receiver will carry out the instructions since the message contains a valid signature.

To prevent this attack we need to remember the assumption from the previous lecture about public channels.

Solution

We need to ensure that attached signature can only be used once:

  • Attach salt to the payload that is randomly generated by client
  • Attach timestamp
  • Any other context information that is specific to the message

Popular signature schemes

  • ECDSA
    • ECDSA (Bitcoin/Ethereum)
    • ECDSA complicates more advanced cryptographic techniques, like threshold signatures.
  • Ed25519 (course)
    • Schnorr signature
    • Fast single-signature verification
    • Even faster batch verification
    • Very fast signing (20-30x faster than ECDSA signatures.)
    • Fast key generation

Key derivation

Key derivation allows one to derive (virtually limitless) child keys from one "parent".

Can be hard. Can be soft

Hard key derivation

Hard key derivation derives a child private key from the parent's private key.

Hard key derivation for wallets

Wallets use this method to derive different keys for different consensus systems.

This method is also useful when you want to generate anonymise us on different network. We can hard derive a key pair from our wallet without revealing the relationship between the derived wallet and the original one.

However,

Compromising parent's private key will compromise all children's private keys!!!

Soft derivation

Allows to create child's public address from the parent's public address. Essentially, all children share the same private key.

Compromising child's private key will compromise parent's private key!!!

Use case: Wallets can use soft derivation to link all payments controlled by a single private key, without the need to expose the private key for the address derivation.

Mnemonics

It would be very inconvenient to store or memorise a byte array.

The common practice is to use some random phrases of 12-24 words to generate a key-pair. This words are often randomly chose from BIP39 English dictionary. The phrase is usually applied 2,048 rounds of the SHA-512 hash function to derive a 64 byte key.

You can use your own phrase or any sort of data to generate a key pair, but please don't

Threshold Multi-Signatures

Sometimes, we want multiple parties to have control over some operations instead of one.

Like sending 10BTC to German's Wallet

That's where multi-signature schemes become useful. We can make the system expect at least k/n signatures to be provided for the transaction to be valid.

Types of Multi-Signature

  • Verifier enforced
  • Cryptographic threshold
  • Cryptographic non-threshold (a.k.a. signature aggregation)

Additional reading