Workshop files used for Blockchain Developer Seminar: Applied Rust for Protocol Development
We will send out finished projects after each tutorial. Code demonstration will be given live. If you prefer following along more than welcome to. We will release a video and a finalized codebase later this week.
To run this project, make sure we have the latest rustc
version, which is the official compiler for Rust.
Update to the latest version by running
rustup update
A python client is located in the client folder. It will be our means of interacting with our rust server.
To run the client, install request package from pip and locate to the client folder.
pip install request
cd ./client/
and run the python code.
python client.py
// should print "true"
for Topic 1,
This tutorial instructs how to build a simple web RPC server and test it with clients, and it uses JSON-RPC 2.0 specification to exchange data.
JSON-RPC is a light-weight remote procedure call (RPC) protocol. Its lightness attracted many blockchain projects to adopt this to their protocol.
Blockchain projects using this specification are:
- Parity(they even implemented this specification by themselves in Rust)
- Ethereum
- Bitcoin
- Ripple
...and many more
If the project cannot be compiled, update rust with rust version manager rustup
rustup update
Navigate to the directory of this project from the cloned repository on terminal and build the project
cd ./Topic1/01_simple_web_server/
cargo build
then run the project.
cargo run
afterwards, to run executable
./target/debug/rust_crypto
Client sends request to RPC server and it is implemented in blockchain and wallets.
It sends two types of params
or as an object:
{
"jsonrpc": "2.0",
"method": "say_hello",
"params": {"name": "Hyungsuk Kang"},
"id":1
}
Make API with the interface to send corresponding json to RPC endpoints then you get:
- web3.js
- web3.py
- web3j
- web3swift
- polkadot-api
For tutorial we will use Postman, but you can also test your server with the client file built here
Press send button and you have now finished a RPC-JSON server development!
as
- perform primitive casting, disambiguate the specific trait containing an item, or rename items in use and extern crate statements
break
- exit a loop immediately
const
- define constant items or constant raw pointers
continue
- continue to the next loop iteration
crate
- link an external crate or a macro variable representing the crate in which the macro is defined
dyn
- dynamic dispatch to a trait object
else
- fallback for if and if let control flow constructs
enum
- define an enumeration
extern
- link an external crate, function, or variable
false
- Boolean false literal
fn
- define a function or the function pointer type
for
- loop over items from an iterator, implement a trait, or specify a higher-ranked lifetime
if
- branch based on the result of a conditional expression
impl
- implement inherent or trait functionality
in
- part of for loop syntax
let
- bind a variable
loop
- loop unconditionally
match
- match a value to patterns
mod
- define a module
move
- make a closure take ownership of all its captures
mut
- denote mutability in references, raw pointers, or pattern bindings
pub
- denote public visibility in struct fields, impl blocks, or modules
ref
- bind by reference
return
- return from function
Self
- a type alias for the type implementing a trait
self
- method subject or current module
static
- global variable or lifetime lasting the entire program execution
struct
- define a structure
super
- parent module of the current module
trait
- define a trait
true
- Boolean true literal
type
- define a type alias or associated type
unsafe
- denote unsafe code, functions, traits, or implementations
use
- bring symbols into scope
where
- denote clauses that constrain a type
while
- loop conditionally based on the result of an expression
This tutorial teaches how ECDSA works and builds ring signatures based on rust bindings of secp256k1 C++ library which is used in Bitcoin.
RSA is an asymmetric algorithm that can be used for encryption and signing. The related algorithm for creating a shared secret symmetric key (key exchange) is Diffie-Hellman. RSA bases its security on the difficulty of integer factorization, while Diffie-Hellman uses the difficulty of finding discrete logarithms. Using RSA directly is often impossible, it works on integers and the operations are quite slow. That creates a need for padding (making messages the right size) and makes it impractical to encrypt or sign large amounts of data directly. These issues (and some others) make RSA fragile: it's easy to screw up the implementation of the padding system or the actual encryption/signing to leak data. Bleichenbacher's Oracle (found in 1998) was an attack on RSA with bad padding implementations. A few days ago it was found to still be present in some major implementations.
DSA uses a very similar process to RSA signing internally, but specifies the particular key generation and hashing steps needed to create signatures properly. More importantly it bases its security not over the difficulty of integer factorization but on the difficulty of the discrete logarithm problem. DSA is only for signatures, not for encryption or key exchange. Unfortunately DSA and ECDSA are fragile: it requires a value to be chosen at random for each signature created. Failure to do this properly results in leaking the private key. The leak of the Sony Playstation 3 DRM key was due to this failure. There are also some easy ways to accidentally leak timing information.
ECDSA is very similar to DSA, but uses elliptic curve cryptography (ECC). ECC uses a different trapdoor function than RSA. Its security is based on the difficulty of the elliptic curve discrete logarithm problem. It allows for smaller key sizes than DSA, and is a good bit faster, but suffers from the same fragility as DSA (and RSA). This ECDSA type of cryptography is what we will primarily cover in this tutorial. It also the standard for almost all blockchains
EdDSA is an alternative to ECDSA designed not to have the fragility issues that DSA/ECDSA/RSA have. It's also faster. If you have a choice of signature algorithms this is the one to use.
X25519 is a form of Elliptic-Curve Diffie-Hellman (ECDH) algorithm. It's used for key exchange. It's very fast and quite robust. If you have a choice of key exchange algorithms this is the one to use.Due to the very slow speed of even the very fast asymmetric systems compared to current symmetric systems it's pretty rare to need to encrypt something directly with an asymmetric system. Instead it's common to use a key exchange algorithm and then a symmetric cryptosystem to send the actual message. For example use EdDSA to prove identity, X25519 to exchange keys, and ChaCha20-Poly1305 for the actual encrypted messages.
Two of the best-known uses of public key cryptography are:
Public key encryption, in which a message is encrypted with a recipient's public key. The message cannot be decrypted by anyone who does not possess the matching private key, who is thus presumed to be the owner of that key and the person associated with the public key. This is used in an attempt to ensure confidentiality.
Digital signatures, in which a message is signed with the sender's private key and can be verified by anyone who has access to the sender's public key. This verification proves that the sender had access to the private key, and therefore is likely to be the person associated with the public key. This also ensures that the message has not been tampered with, as a signature is mathematically bound to the message it originally was made with, and verification will fail for practically any other message, no matter how similar to the original message.
Symmetric cryptography is often compared to lock and key as
key : lock :: secret key : encryped data
This secures data from others it also certifies that the data belongs to a person.
However, on a network protocol where nodes are sharing data between blockchain nodes, it is meaningless to use the cryptography since everyone is able to reproduce with the shared keys.
To overcome this, we apply asymmetric cryptography, which there is one key to only encrypt the data, and the other to decrypt only.
Signing key is called private key, and verifying key for decryption is called public key.
Eliptic Curve Digital Signature Algorithm(ECDSA) is one of asymmetric cryptography. ECDSA uses two systems to encrypt the data; eliptic curve and finite field(Galois field).
Eliptic curve arithmetic is one-way and multiplication can be applied with repeating addition only. This makes it hard to undo operations to find the original value, which is the private key.
as
- perform primitive casting, disambiguate the specific trait containing an item, or rename items in use and extern crate statements
break
- exit a loop immediately
const
- define constant items or constant raw pointers
continue
- continue to the next loop iteration
crate
- link an external crate or a macro variable representing the crate in which the macro is defined
dyn
- dynamic dispatch to a trait object
else
- fallback for if and if let control flow constructs
enum
- define an enumeration
extern
- link an external crate, function, or variable
false
- Boolean false literal
fn
- define a function or the function pointer type
for
- loop over items from an iterator, implement a trait, or specify a higher-ranked lifetime
if
- branch based on the result of a conditional expression
impl
- implement inherent or trait functionality
in
- part of for loop syntax
let
- bind a variable
loop
- loop unconditionally
match
- match a value to patterns
mod
- define a module
move
- make a closure take ownership of all its captures
mut
- denote mutability in references, raw pointers, or pattern bindings
pub
- denote public visibility in struct fields, impl blocks, or modules
ref
- bind by reference
return
- return from function
Self
- a type alias for the type implementing a trait
self
- method subject or current module
static
- global variable or lifetime lasting the entire program execution
struct
- define a structure
super
- parent module of the current module
trait
- define a trait
true
- Boolean true literal
type
- define a type alias or associated type
unsafe
- denote unsafe code, functions, traits, or implementations
use
- bring symbols into scope
where
- denote clauses that constrain a type
while
- loop conditionally based on the result of an expression
If the project cannot be compiled, update rust with rust version manager rustup
rustup update
Navigate to the directory of this project from the cloned repository on terminal and build the project
cd ./Topic1/01_simple_web_server/
cargo build
then run the project.
cargo run
afterwards, to run executable
./target/debug/rust_crypto
In this project, we have managed bits and bytes for you to easily generate private(secret)/public keys and sha256 hash from struct.
mod ecdsa;
let (sk, pk) = ecdsa::generate();
println!("secret_key: {}, public_key:{}", sk, pk);
/* prints secret_key: 3397b8b6faba3f83925dcffb51773a28f59530dd3cb6fccf6e3518094040ff70, public_key:022da9ebc229b9436ae89781e12b5787c5e26c3bf555e522b500443df637a9a873 */
let signature = sign_raw(&sk, txhash);
println!("{}", signature);
/* prints 304402207eaa99cac098aed4cfd7779aae6fd5e547cfaefda81383b83cc4b3a4b01defeb02201b7dc1f51093896301a674a70e0cd037567a65aa3a89066efaf1d64eea7e8d840000 */
let data = "Bob sends Alice to 5 eth";
let mut tx: Transaction = Transaction::new(&alice_pk, &bob_pk, 5, data);
/* returns Transaction { timestamp: 1549893371, to: "022337a6ba0c0229fb48469bd49745b200f4cdb35459e7033dbd846bee66ee87be", sender: "02a03b99517daf92dd3925eaf02cc5b6e9a90314a70baaa22e7e5383b1580df730", amount: 5, signature: "304402202f8046faf00d945a74c0f42e7e05c7a8360ff4681d57b524c5da79bc2d2058f80220456fe85f731fa07a17361963198c47f2dfd4ee5b6ea9d9932d8a6626ba53d4fe0000", data: "Bob sends Alice to 5 eth" } */
let txhash = tx.defunc_hash();
println!("{:?}", txhash);
/* prints 32 byte array [97, 47, 223, 9, 131, 127, 59, 167, 82, 210, 232, 206, 47, 113,230, 43, 242, 9, 8, 35, 210, 158, 74, 51, 112, 152, 225, 162, 70, 229, 186, 88] */
In this topic, we will build a transaction authentication/authorization server with ECDSA and json-rpc 2.0. We already built interfaces from Topic 1-2 for you to avoid going through bits and bytes so don't worry.
The authentication server has only one endpoint which verifies transaction.
- verify_transaction
Returns whether transaction is valid or not with boolean value.
timestamp
: the time when the transaction was processed
to
: recipient(in public key/ encoded address) of the asset
sender
: sender of the asset and prover of the transaction
amount
: amount of the asset to send
signature
: signature generated from the sender's private(secret) key
data
: message or reference for the transaction
bool
- whether the transaction is valid(true) or not(false)
// Request
curl -X POST \
http://localhost:3031/ \
-H 'Content-Type: application/json' \
-H 'Postman-Token: 9e701109-5663-4b24-91d5-183d7a72019c' \
-H 'cache-control: no-cache' \
-d '{
"jsonrpc": "2.0",
"method": "verify_transaction",
"params": {"timestamp": 1549893371, "to": "022337a6ba0c0229fb48469bd49745b200f4cdb35459e7033dbd846bee66ee87be", "sender": "02a03b99517daf92dd3925eaf02cc5b6e9a90314a70baaa22e7e5383b1580df730", "amount": 5, "signature": "304402202f8046faf00d945a74c0f42e7e05c7a8360ff4681d57b524c5da79bc2d2058f80220456fe85f731fa07a17361963198c47f2dfd4ee5b6ea9d9932d8a6626ba53d4fe0000", "data": "Bob sends Alice to 5 eth" },
"id":1
}'
// Result
{
"jsonrpc": "2.0",
"result": "true",
"id": 1
}
A python client is located in the client folder.
To run the client, install request package from pip and locate to the client folder.
pip install request
cd ./client/
and run the python code.
python client.py
//should print "true"
WebAssembly is a new assembly language close to metal which is shared all types of major browsers.
It started as an upgrade to javascript, which is the only programming language on the web browser to be compiled on native level. However, all programming languages now try to support it to be compiled in the assembly language so that they can be compiled to the web without using javascript.
Rust is one of them but has more advantages than other languages with its memory-safe compiler without garbage collection. Compiled wasm from Rust has less wasm code and memory-safe on development.
To witness the power of WebAssembly in rust, check out
https://github.com/rustwasm/awesome-rust-and-webassembly
In this topic, we will make node package with wasm.
- Set nightly version as default
rustup default nightly
-
Start new rust project with
Cargo new wasm-tutorial
-
Set Cargo.toml as below:
[package]
name = "wasm-tutorial"
version = "0.1.0"
authors = ["hskang9 <[email protected]>"]
edition = "2018"
[lib]
crate-type = ["cdylib"] // only static library is supported on wasm for now
[dependencies]
wasm-bindgen="0.2"
To enable the functions created from the rust on browser, we need to build a wrapper interface to be run on js file. You can think of this as importing javascript function to rust file.
extern create wasm_bindgen;
use wasm_bindgen::prelude::*;
// Wrapper interface
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
With wasm-bindgen, you can also export rust code with javascript functions.
#[wasm_bindgen]
pub fn hello_world(name: &str) {
alert(&format!("Hello, {}!", name));
}
Now javascript is a compiled language with the wasm. build the package by running this command.
wasm-pack build
Then go to pkg folder and you can use npm commands for this.
cd pkg/
npm publish --access=public