Skip to content
Snippets Groups Projects
Commit 2e4315ca authored by Gerui Wang's avatar Gerui Wang
Browse files

warmup

parents
No related branches found
No related tags found
No related merge requests found
/target
debug/
target/
**/*.rs.bk
.idea
.DS_Store
LICENSE 0 → 100755
MIT License
Copyright (c) 2019 Prism Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Principles of Blockchains
Welcome! This is the repository for ECE 598 PV: Principles of Blockchains, Spring 2022 at University of Illinois, Urbana-Champaign. [Main website of the course](https://courses.grainger.illinois.edu/ece598pv/sp2022/).
## Discussion
We use Piazza for discussion.
## Project Suggestion
You need to run the project on your machines. **We strongly recommend Linux or Mac OS.**
## Warmup Project
- [Warmup 1](Warmup1). Due date: 12:30pm CT, Jan 25, 2022.
- [Warmup 2](Warmup2). Due date: 12:30pm CT, Feb 1, 2022.
## Midterm Project
- Team formation. Please form teams of 2 for this project. Due date: same as warmup 2.
## Policy
Submissions later than due date will get 0 points.
\ No newline at end of file
# Warmup 1
Hi, welcome! This is your first assignment of this course. The goal of this assignment is to let you get familiar with the **Rust** programming language. We will use Rust throughout this course so it is a good idea to start to learn it as early as possible.
## Introduction
We expect that you are familiar with at least one programming language so that you have some experience with programming. If you don't know Rust language, it is totally okay since in this assignment, you'll self-teach Rust language by reading the documents of:
- the Rust language itself;
- Cargo, the rust package manager and building tool;
- Rust standard libraries;
- Rust crates.
Then you will finish simple tasks in the codebase we provide. If you are already familiar with Rust, this simple assignment will take less than 30 minutes!
**Notice that this is an individual assignment. You should finish it on your own.**
## Reading
Please read [Rust by example](https://doc.rust-lang.org/rust-by-example/) to learn Rust grammar.
Please read [https://doc.rust-lang.org/cargo/](https://doc.rust-lang.org/cargo/) to learn Cargo, the Rust package manager and building tool. After reading chapter 1, you'll be able to install Rust and Cargo, and run a Rust project.
For [Rust standard crate](https://doc.rust-lang.org/stable/std/), we recommend you to learn two very important structs: **String** and **Vec**.
You can learn about other public crates here: [https://docs.rs/](https://docs.rs/). A *crate* just means a library or a package, and can be managed by Cargo. You will learn how to use the following crate:
- [ring](https://docs.rs/ring/0.16.20/ring/), a cryptographic crate. Specifically, you need to learn how to do SHA256 hash.
For these crates, their github page or homepage may also be helpful. Feel free to read them.
## Repository management and submission:
1. This repo provides the codebase for assignments. Please fork the current repo. **Change visibility to private.** Note: We are also going to use the same repo, which means you don't need to fork this repo again in the future.
2. You can run tests (by command `cargo test`) provided in the code to check the validity of their implementation. However, passing these tests doesn't guarantee getting full grades.
3. Push to your gitlab repo's **main** branch (Hint: use `gitignore` file to avoid pushing unnecessary files!), and click `Download' on gitlab to download a zip file. **Avoid zipping your code on your computer, since the directories or files on your computer may cause error for auto-grading.**
4. Before submitting your code, you can double check by running the auto-grading script we provide to make sure we can auto-grade your code. (Details below.)
5. Rename it to your netid as `netid.zip`. Upload the zip file on compass2g. Please check your file size and it should not be very large.
6. TAs will put additional tests (private) to the auto-grader and run them to award marks.
## Code provided
We have provided incomplete code for implementing some crypto-primitives. The following files are related to this assignment.
_src/types/address.rs_ - Provides __Address__ struct (20 byte array).
_src/types/transaction.rs_ - struct defition of **Transaction** struct and function declaration for __sign()__ and __verify()__ .
As for other files in the repo, you don't have to worry about them in this assignment. They may appear in future assignments/projects.
## Programming
After you fork this repo, the first thing we suggest is to run command `cargo test` to see whether the code is compiling on your machine. (If compiling has error, please check the version of cargo to be the latest stable.) If the compiling is successful, you will see something like this:
```
running X tests
test XXX ... FAILED
test XXX ... FAILED
```
It's expected that tests fail with the code we provide. After you finish this assignment, some of the tests will pass. Feel free to add your tests to your code as well.
These are the tasks of this assignment:
1. You need to implement the missing parts in file _src/types/address.rs_:
- `fn from_public_key_bytes(bytes: &[u8])`
- It uses SHA256 (from **ring** crate) to hash the input bytes, and takes the last 20 bytes and convert them into a __Address__ struct. The code now contains `unimplemented!()` and you can delete it and write your own code.
- We provide a small test function named **from_a_test_key()**. After you finished coding, you can run `cargo test from_a_test_key` and you can see the result of this function in the output. It will look like the following.
```
test types::address::test::from_a_test_key ... ok
```
- To test your code, you are free to write more tests.
2. The missing parts in file _src/types/transaction.rs_:
- Fill in the **Transaction** struct. Up to now we don’t expect the cryptocurrency and payment to be functional, so you can put any content in transactions. A simple choice is to put **sender**, **receiver**, and **value** inside transactions. **sender**, **receiver** are of type **Address** and **value** is integer.
- Fill in the `sign` and `verify` function. These two function should sign and verify the digital signature of the **Transaction** struct. Please use **ring** crate. The code we provide contains some `unimplemented!()` and you can delete it and write your own code.
- A tricky part about transaction and signature is how you put them together. Hence, we provide another struct called **SignedTransaction**. You can let this struct have a transaction, a signature, and a public key who creates the signature. Notice that crate *ring*'s signature and public key structs may not be very convenient to use, so you can convert them to vector of bytes: `let signature_vector: Vec<u8> = signature.as_ref().to_vec();`
- For testing, you need to fill in the function **generate_random_transaction()** which will generate a random transaction on each call. It should generate two different transactions on two calls. We require this since we are going to use this function many times in our test and grading. Again, there is `unimplemented!()` and you can delete it.
- We provide a small test function named **sign_verify()**. After you finished, you can run `cargo test sign_verify` / `sign_verify_two` and you can see the result of this function in the output. It will look like the following.
```
test types::transaction::tests::sign_verify ... ok
```
- To test your code, you are free to write more tests.
## Double check
We provide (incomplete) auto-grader for you to test that your code format fits auto-grader. However, passing this auto-grader doesn't guarantee getting full grades. For this assignment, put your netid.zip file with [autograder.sh](autograder.sh) and [add_test.py](add_test.py) in a new directory, from where run
```
bash autograder.sh
```
And you can open the output file _log.txt_, and see whether the auto-grader's tests are passed. You need to have `bash`, `unzip`, and `python3` to run this double check.
If you see "Code format wrong" on screen, your code may change the lines that should not be changed like this: `// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER.`
If in _log.txt_ you cannot see correct log, your zip file may have incorrect directories for auto-grader to compile.
## Submission
Download the zip file of your repo on gitlab. Rename it to your netid as `netid.zip`. Upload the zip file on compass2g. Please check your file size and it should not be very large.
## Advance Notice
- At the end of the course, you will implement a functional cryptocurrency client based on this codebase. So it is helpful to get familiar with this codebase.
- This code base provides other files that will help you build a blockchain client. If you want to run the main program and see what is going on, you can run `cargo run -- -vv`. Currently the main program just stucks at a loop. (`-vv` is for level 2 logging, you can have `-vvv` for level 3.)
- At the end of the project, you will implement a functional cryptocurrency client. In this assignment we provide a temporary option of transaction that contains sender, receiver, and value. You can think of the transaction struct that can support a real cryptocurrency, and look up the way Bitcoin and Ethereum do.
test_code = r'''
#[cfg(test)]
mod test {
use super::Address;
#[test]
fn sp2022autograder001() {
let test_key = hex!("0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d");
let addr = Address::from_public_key_bytes(&test_key);
let correct_addr: Address = hex!("1851a0eae0060a132cf0f64a0ffaea248de6cba0").into();
assert_eq!(addr, correct_addr);
}
}
'''
test_code_2 = r'''
#[cfg(test)]
mod tests {
use super::*;
use crate::types::key_pair;
use ring::signature::KeyPair;
#[test]
fn sp2022autograder002() {
let t = generate_random_transaction();
let key = key_pair::random();
let signature = sign(&t, &key);
assert!(verify(&t, key.public_key().as_ref(), signature.as_ref()));
}
#[test]
fn sp2022autograder003() {
let t = generate_random_transaction();
let key = key_pair::random();
let signature = sign(&t, &key);
let key_2 = key_pair::random();
let t_2 = generate_random_transaction();
assert!(!verify(&t_2, key.public_key().as_ref(), signature.as_ref()));
assert!(!verify(&t, key_2.public_key().as_ref(), signature.as_ref()));
}
}
'''
import re
import sys
import os.path as path
file_path = path.join(sys.argv[1], 'src/types/address.rs')
print(path.dirname(file_path), end=' ')
before_pat = r'// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER. BEFORE TEST'
after_pat = r'// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER. AFTER TEST'
change_before = False
change_after = False
file_changed = []
with open(file_path) as fin:
for line in fin:
if after_pat in line:
change_after = True
if not change_before or change_before and change_after:
file_changed.append(line)
if before_pat in line:
change_before = True
file_changed.append(test_code)
if change_before and change_after:
print("\033[92m {}\033[00m".format("Changed the test code"))
with open(file_path, "w") as fout:
fout.write(''.join(file_changed))
else:
print("\033[91m {}\033[00m".format("Code format wrong"))
file_path = path.join(sys.argv[1], 'src/types/transaction.rs')
print(path.dirname(file_path), end=' ')
before_pat = r'// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER. BEFORE TEST'
after_pat = r'// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER. AFTER TEST'
change_before = False
change_after = False
file_changed = []
with open(file_path) as fin:
for line in fin:
if after_pat in line:
change_after = True
if not change_before or change_before and change_after:
file_changed.append(line)
if before_pat in line:
change_before = True
file_changed.append(test_code_2)
if change_before and change_after:
print("\033[92m {}\033[00m".format("Changed the test code"))
with open(file_path, "w") as fout:
fout.write(''.join(file_changed))
else:
print("\033[91m {}\033[00m".format("Code format wrong"))
\ No newline at end of file
# put this file, add_test.py, and your netid.zip file in a new directory
for zipfile in *.zip; do
netid=${zipfile%%.*}
unzip -qq $zipfile -d $netid
if [ -d $netid ]; then
echo "student netid: $netid" >> log.txt
python3 add_test.py $netid/ece598pv-sp2022-main
cd $netid/ece598pv-sp2022-main
cargo test sp2022autograder00 >> ../../log.txt 2>> build_log.txt
cd ../..
fi
done
#grep 'student netid\|test result' log.txt > result.txt
\ No newline at end of file
# Warmup 2
In this assignment, you will implement some crypto-primitives and basic data structures. You will need the code that we provide in this repo. Please follow the instructions.
**Notice that this is team (of two teammates) assignment. The team makes a joint submission.**
## Repository management and submission:
1. Similar to the previous assignment, you can continue to work on your gitlab repo. After pushing to your gitlab repo, click `Download' on gitlab to download a zip file.
2. Rename it to your netids as `netid1-netid2.zip`. Sort netids in alphabetic order. Upload the zip file on compass2g. Please check your file size and it should be less than 1MB or 2MB. **Submission from one team member is sufficient.**
3. TAs will put additional tests (private) on the submission and run them to award marks.
## Code provided
We have provided incomplete code for implementing some crypto-primitives and data structures like merkle tree. The following files are related to this assignment and you should read them.
1. _src/types/hash.rs_ - Provides __H256__ struct(32 byte array), __Hashable__ trait, with its implementation for H256. (You don't need to write anything in this file.)
2. _src/types/merkle.rs_ - struct defition of **MerkleTree** struct and the related function declaration
You will write your code in this file.
As for other files in the repo, you don't have to worry about them in this assignment. They may appear in future assignments/projects.
## Programming
You need to implement the missing parts in the code. They include the following.
### Merkle Tree
This part is in file *src/types/merkle.rs*. You need to complete the merkle tree struct and some functions. You can find a good article about it [here](https://nakamoto.com/merkle-trees/). Specifically, the functions you need to implement are:
1. *new()* - this function takes a slice of Hashable data as input, and create the merkle tree.
2. *root()* - given a merkle tree, return the root. The computation of the root is inside *new()*, this function should just return the root.
3. *proof()* - given a merkle tree, and also given the index, this function returns the proof in the form of a vector of hashes.
4. *verify()* - given a root, a hash of datum, a proof (a vector of hashes), an index of that datum (same index in *proof()* function), and a leaf_size (the length of leaves/data in *new()* function), returns whether the proof is correct.
We provide some small test functions in this file and you can run `cargo test`. In these test functions, we also provide a brief explanation about the expected computation.
*new()* function can take any Hashable data, but for simpilicity we will test merkle tree over **H256**, whose Hashable trait is already provided inside *src/types/hash.rs*.
A tricky part about *new()* is when the input length is not a power of 2, you will need some more steps to create the merkle tree as follows.
> Whenever a level of the tree has odd number of nodes, duplicate the last node to make the number even.
## Grading
After you finish the programming, you can run `cargo test merkle_root` / `merkle_proof` / `merkle_verifying` to test whether your implementation is working.
We will auto-grade the program using tests that are similar to the aforementioned tests. For merkle tree tests, we will use an input of length 8.
## Double check
We provide (incomplete) auto-grader for you to test that your code format fits auto-grader. However, passing this auto-grader doesn't guarantee getting full grades. For this assignment, put your zip file with [autograder.sh](autograder.sh) and [add_test.py](add_test.py) in a new directory, from where run
```
bash autograder.sh
```
And you can open the output file _log.txt_, and see whether the auto-grader's tests are passed. You need to have `bash`, `unzip`, and `python3` to run this double check.
test_code = r'''
#[cfg(test)]
mod tests {
use crate::types::hash::H256;
use super::*;
macro_rules! gen_merkle_tree_data {
() => {{
vec![
(hex!("0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d")).into(),
(hex!("0101010101010101010101010101010101010101010101010101010101010202")).into(),
]
}};
}
#[test]
fn sp2022autograder011() {
let input_data: Vec<H256> = gen_merkle_tree_data!();
let merkle_tree = MerkleTree::new(&input_data);
let root = merkle_tree.root();
assert_eq!(
root,
(hex!("6b787718210e0b3b608814e04e61fde06d0df794319a12162f287412df3ec920")).into()
);
// "b69566be6e1720872f73651d1851a0eae0060a132cf0f64a0ffaea248de6cba0" is the hash of
// "0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d0a0b0c0d0e0f0e0d"
// "965b093a75a75895a351786dd7a188515173f6928a8af8c9baa4dcff268a4f0f" is the hash of
// "0101010101010101010101010101010101010101010101010101010101010202"
// "6b787718210e0b3b608814e04e61fde06d0df794319a12162f287412df3ec920" is the hash of
// the concatenation of these two hashes "b69..." and "965..."
// notice that the order of these two matters
}
#[test]
fn sp2022autograder012() {
let input_data: Vec<H256> = gen_merkle_tree_data!();
let merkle_tree = MerkleTree::new(&input_data);
let proof = merkle_tree.proof(0);
assert_eq!(proof,
vec![hex!("965b093a75a75895a351786dd7a188515173f6928a8af8c9baa4dcff268a4f0f").into()]
);
// "965b093a75a75895a351786dd7a188515173f6928a8af8c9baa4dcff268a4f0f" is the hash of
// "0101010101010101010101010101010101010101010101010101010101010202"
}
#[test]
fn sp2022autograder013() {
let input_data: Vec<H256> = gen_merkle_tree_data!();
let merkle_tree = MerkleTree::new(&input_data);
let proof = merkle_tree.proof(0);
assert!(verify(&merkle_tree.root(), &input_data[0].hash(), &proof, 0, input_data.len()));
}
}
'''
import re
import sys
import os.path as path
file_path = path.join(sys.argv[1], 'src/types/merkle.rs')
print(path.dirname(file_path), end=' ')
before_pat = r'// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER. BEFORE TEST'
after_pat = r'// DO NOT CHANGE THIS COMMENT, IT IS FOR AUTOGRADER. AFTER TEST'
change_before = False
change_after = False
file_changed = []
with open(file_path) as fin:
for line in fin:
if after_pat in line:
change_after = True
if not change_before or change_before and change_after:
file_changed.append(line)
if before_pat in line:
change_before = True
file_changed.append(test_code)
if change_before and change_after:
print("\033[92m {}\033[00m".format("Changed the test code"))
with open(file_path, "w") as fout:
fout.write(''.join(file_changed))
else:
print("\033[91m {}\033[00m".format("Code format wrong"))
# put this file, add_test.py, and your netid.zip file in a new directory
for zipfile in *.zip; do
netid=${zipfile%%.*}
unzip -qq $zipfile -d $netid
if [ -d $netid ]; then
echo "student netid: $netid" >> log.txt
python3 add_test.py $netid/ece598pv-sp2022-main
cd $netid/ece598pv-sp2022-main
cargo test sp2022autograder01 >> ../../log.txt 2>> build_log.txt
cd ../..
fi
done
#grep 'student netid\|test result' log.txt > result.txt
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment