aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYigit Sever2021-04-19 18:23:22 +0300
committerYigit Sever2021-04-19 18:23:22 +0300
commit59ea3bd25b1f113168333eccdc9ffc4acd98cfe6 (patch)
tree4d76d4423f7d47755890aa98cbf0751978ef9180
downloadgradecoin-site-59ea3bd25b1f113168333eccdc9ffc4acd98cfe6.tar.gz
gradecoin-site-59ea3bd25b1f113168333eccdc9ffc4acd98cfe6.tar.bz2
gradecoin-site-59ea3bd25b1f113168333eccdc9ffc4acd98cfe6.zip
Initial commit
-rw-r--r--README.md10
-rw-r--r--config.toml28
-rw-r--r--content/JWT.md41
-rw-r--r--content/_index.md98
-rw-r--r--content/block_docs.md43
-rw-r--r--content/misc_docs.md17
-rw-r--r--content/register_docs.md54
-rw-r--r--content/transaction_docs.md52
-rw-r--r--static/android-chrome-192x192.pngbin0 -> 26249 bytes
-rw-r--r--static/android-chrome-512x512.pngbin0 -> 80376 bytes
-rw-r--r--static/apple-touch-icon.pngbin0 -> 24023 bytes
-rw-r--r--static/favicon-16x16.pngbin0 -> 878 bytes
-rw-r--r--static/favicon-32x32.pngbin0 -> 2463 bytes
-rw-r--r--static/favicon.icobin0 -> 15406 bytes
-rw-r--r--static/gradecoin.pngbin0 -> 197656 bytes
-rw-r--r--static/gradecoin.pub9
-rw-r--r--static/site.css57
-rw-r--r--templates/_variables.html15
-rw-r--r--templates/index.html68
-rw-r--r--templates/shortcodes/exp.html1
-rw-r--r--templates/shortcodes/tidbit.html5
21 files changed, 498 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a4415af
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
1# Gradecoin Site
2URL: https://gradecoin.xyz/
3
4Uses [Zola](http://getzola.org/).
5
6```bash
7zola serve --open # for local building & testing
8zola build
9```
10
diff --git a/config.toml b/config.toml
new file mode 100644
index 0000000..070b762
--- /dev/null
+++ b/config.toml
@@ -0,0 +1,28 @@
1# The URL the site will be built for
2base_url = "https://gradecoin.xyz"
3
4theme = "juice"
5
6title = "Gradecoin"
7description = "Mine Your Grades"
8
9# Whether to automatically compile all Sass files in the sass directory
10compile_sass = true
11
12# Whether to build a search index to be used later on by a JavaScript library
13build_search_index = true
14
15[markdown]
16# Whether to do syntax highlighting
17# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
18highlight_code = true
19highlight_theme = "subway-moscow"
20
21[extra]
22# Put all your custom variables here
23juice_logo_name = "Gradecoin"
24juice_logo_path = "gradecoin.png"
25juice_extra_menu = [
26 { title = "why?", link = "https://github.com/zhuowei/nft_ptr#why"}
27]
28
diff --git a/content/JWT.md b/content/JWT.md
new file mode 100644
index 0000000..46da1a2
--- /dev/null
+++ b/content/JWT.md
@@ -0,0 +1,41 @@
1+++
2title = "JWT"
3description = "JSON Web Token Documentation"
4weight = 4
5+++
6
7> JSON Web Tokens are representations of claims, or authorization proofs that fit into the `Header` of HTTP requests.
8
9# How?
10
11JWTs are used as the [MAC](https://en.wikipedia.org/wiki/Message_authentication_code) of operations that require authorization:
12- block proposal
13- transaction proposal.
14
15They are send alongside the JSON request body in the `Header`;
16
17```html
18Authorization: Bearer aaaaaa.bbbbbb.ccccc
19```
20
21Gradecoin uses 3 fields for the JWTs;
22
23```json
24{
25"tha": "Hash of the payload, check invididual references",
26"iat": "Issued At, Unix Time",
27"exp": "Expiration Time, epoch"
28}
29```
30
31- `tha` is explained in [blocks](@/block_docs.md) and [transactions](@/transaction_docs.md) documentations.
32- `iat` when the JWT was created in [Unix Time](https://en.wikipedia.org/wiki/Unix_time) format
33- `exp` when the JWT will expire & be rejected in [Unix Time](https://en.wikipedia.org/wiki/Unix_time)
34
35# Algorithm
36We are using [RS256](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1), `RSASSA-PKCS1-v1_5 using SHA-256`. The JWTs you encode with your private RSA key will be decoded using the public key you have authenticated with. You can see how the process works [here](https://jwt.io/).
37
38# References
39- [RFC, the ultimate reference](https://tools.ietf.org/html/rfc7519)
40- [JWT Debugger](https://jwt.io/)
41
diff --git a/content/_index.md b/content/_index.md
new file mode 100644
index 0000000..d0be673
--- /dev/null
+++ b/content/_index.md
@@ -0,0 +1,98 @@
1+++
2title = "Gradecoin"
3sort_by = "weight"
4+++
5
6# Welcome to Gradecoin!
7
8Blockchains are incredibly simple yet can appear very complicated, we will see how they work and practice programming _production_ cryptography code.
9
10This server is the sandbox for the PA1, it's currently running the Gradecoin application. Gradecoin is the faux currency we will use to simulate a blockchain network. At the end of the simulation, the amount of Gradecoin you hold will be your PA1 grade.
11
12**A quick summary**: authenticate yourself to the system using public key encryption.
13Craft [Transaction](@/transaction_docs.md) proposals and tag them using [JWTs](@/JWT.md).
14When there are enough transactions then you can propose [Blocks](@/block_docs.md) in the same way.
15Blocks need to be _mined_ beforehand using Proof-of-work, or brute force.
16
17Gradecoin offers 3 endpoints at [/register](/register), [/block](/block) and [/transaction](/transaction). You can only send GET requests to /block and /transaction without authorization.
18The server is programmed in [RESTful](https://www.service-architecture.com/articles/web-services/representational_state_transfer_rest.html) architecture, there are no `DELETE`, `PUT` or `UPDATE` operations, though.
19
20Gradecoin uses a Proof-of-work block accepting mechanism. It uses single round [Blake2s](https://www.blake2.net/) hashing which produces 256-bit (64 hexadecimal characters) output. The [target](https://wiki.bitcoinsv.io/index.php/Target) hash is _24 bits_ or _6 hexadecimal characters_ of 0. During testing, I could mine a block on average around 4-6 minutes.
21
22> We're expecting you to use existing tools and implementations. Standards are hard. [Don't roll your own crypto](https://www.reddit.com/r/crypto/comments/2coqsy/dont_roll_your_own/). Feel free to ask questions. Collaborate.
23
24You might ask,
25
26> But if nobody has any Gradecoin then how do we have transactions?
27
28There is a bank! Their public key is `31415926535897932384626433832795028841971693993751058209749445923` and they have some amount of Gradecoin preloaded. It's also the only account that you can send transactions requests _to_ yourself.
29
30# Coinbase
31The first transactions of a block is called the `coinbase`. They are the **author** of the block proposal and if the block is accepted then they get compensated for their efforts with some Gradecoin.
32
33# Public Key Signatures
34Gradecoin uses 2048 bit RSA keypairs.
35
36# Services
37## /register
38- Create your own 2048 bit RSA `keypair`
39- Download `Gradecoin`'s Public Key from [Moodle](https://odtuclass.metu.edu.tr/my/)
40- Encrypt your [JSON](https://www.json.org/json-en.html) wrapped `Public Key`, `Student ID` and one time `passwd` using Gradecoin's Public Key
41- Your public key is now in our database and can be used to sign your JWT's during requests
42- For more information, check the [register](@/register_docs.md) page
43
44## /transaction
45- You can offer a [Transaction](@/transaction_docs.md) with a POST request
46 - The request should have `Authorization`
47 - The request header should be signed by the Public Key of the `by` field in the transaction
48- Fetch the list of `Transaction`s with a GET request
49- For more information, check our [transaction](@/transaction_docs.md) page
50
51## /block
52- Offer a [Block](@/block_docs.md) with a POST request
53 - The request should have `Authorization`
54 - The `transaction_list` of the block should be a subset of pending transactions, available on [/transaction](/transaction)
55- Fetch the last accepted `Block` with a GET request
56- For more information, check our [block](@/block_docs.md) page
57
58 `Authorization`: The request header should have Bearer JWT.Token signed with Student Public Key
59
60## /user
61- Meant to be used in the browser, you can see the current list of users and their balance here
62
63# Questions
64## This all sound complicated!
65- I've drawn inspiration from [actual Bitcoin transactions](https://explorer.bitcoin.com/btc) and [warp](https://github.com/seanmonstar/warp/blob/master/examples/todos.rs). The simplicity of the system is how little interfaces it has.
66- Don't know where to start? Gradecoin uses RESTful API; simple `curl` commands or even your browser will work! [This website can help as well](https://curl.trillworks.com/).
67- [JWT Debugger](https://jwt.io) and the corresponding [RFC](https://tools.ietf.org/html/rfc7519).
68- Remember that you are absolutely encouraged to grab off-the-shelf implementations for every cryptography primitive you will use. You can start by finding a code snippet to generate a RSA keypair?
69- Check out [misc](@/misc_docs.md) for everything else you might be curious about.
70
71## How do you actually earn Gradecoin?
72- Register yourself to at [/register](@/register_docs.md)
73- Create transactions at [/transaction](@/transaction_docs.md)
74- Create blocks to commit transactions at [/block](@/block_docs.md)
75- See how everyone is doing and find people to trade with at [/user](/user)
76
77## I found a bug!
78Thank you! Please [let me know](mailto:yigit@ceng.metu.edu.tr) so we can solve it.
79
80## I hacked the server!
81That wasn't supposed to happen :( I did not place any intentional vulnerabilities to the system so if you cracked something, it was not intended. Please don't abuse it and let me know so I can patch it.
82
83## Submission?
84At the end of the _simulation_, your Gradecoin balance will be your grade. I will also expect a unique client programmed in either;
85- c
86- c++
87- perl
88- rust
89- python
90- random assortment of bash scripts
91
92If your favourite programming language is missing please let me know 🤷?
93
94## Can my friends play?
95Sadly, no. Student's who are enrolled to the class will receive one-time-passwords for authentication.
96
97## How and or Why?
98- [Built](https://xkcd.com/2314/), [with](https://lofi.cafe/) [Rust](https://xkcd.com/2418/)
diff --git a/content/block_docs.md b/content/block_docs.md
new file mode 100644
index 0000000..92880b6
--- /dev/null
+++ b/content/block_docs.md
@@ -0,0 +1,43 @@
1+++
2title = "Blocks"
3description = "Block Documentation"
4weight = 10
5+++
6
7A block that was proposed to commit Transactions in `transaction_list` to the
8ledger with a nonce that made `hash` valid; 6 zeroes at the left hand side of the
9hash (24 bytes).
10
11We are _mining_ using [blake2s](https://www.blake2.net/) algorithm, which produces 256 bit hashes. Hash/second is roughly {{ exp(num="20x10", exponent="3") }} on my machine, a new block can be mined in around 4-6 minutes.
12
13# Requests
14
15## GET
16A HTTP `GET` request to [/block](/block) endpoint will return the latest mined block.
17
18## POST
19
20A HTTP `POST` request with Authorization using JWT will allow you to propose your own blocks.
21
22# Fields
23```
24transaction_list: [array of Fingerprints]
25nonce: unsigned 32-bit integer
26timestamp: ISO 8601 <date>T<time>
27hash: String
28```
29
30# Mining
31The _mining_ process for the hash involves;
32- Creating a temporary JSON object with `transaction_list`, `timestamp` and `nonce` values
33- Serializing it
34- Calculating blake2s hash of the serialized string
35
36If the resulting hash is valid, then you can create a `Block` JSON object with the found `nonce` and `hash`.
37
38# Hash
39
40```tha``` field in [jwt documentation](/jwt) in fact stands for "The Hash", in the case of a post request for a block, you need to use hash field of the block.
41
42
43[ISO 8601 Reference](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations)
diff --git a/content/misc_docs.md b/content/misc_docs.md
new file mode 100644
index 0000000..90ea514
--- /dev/null
+++ b/content/misc_docs.md
@@ -0,0 +1,17 @@
1+++
2title = "Misc"
3description = "Documentation about everything else"
4weight = 10
5+++
6
7We thought it might be good to explain some concepts you might have questions about.
8
9# Fingerprint
10
11## Definition
12
13A fingerprint is a 256 bit 64 character hexadecimal user identifier for users. Fingerprints are used in defining users in [transactions](@/transaction_docs.md) and [blocks](@/block_docs.md).
14
15## Fingerprint Generation
16
17A user's finger print is generated via applying SHA256 sum of the user's public RSA key.
diff --git a/content/register_docs.md b/content/register_docs.md
new file mode 100644
index 0000000..974fe37
--- /dev/null
+++ b/content/register_docs.md
@@ -0,0 +1,54 @@
1+++
2title = "Register"
3description = "Register Documentation"
4weight = 3
5+++
6
7POST request to `/register` endpoint
8
9Lets a user to authenticate themselves to the system.
10Only people who are enrolled to the class can open Gradecoin accounts.
11This is enforced with your Student ID (e123456) and a one time password you will receive.
12
13# Authentication Process
14
15> The bytes you are sending over the network are all Base64 Encoded
16
17- Gradecoin's Public Key (`gradecoin_public_key`) is listed on our Moodle page and [here](/gradecoin.pub). Download and load it it to your client.
18- Create a JSON object (`P_AR`) with your `metu_id` ("e"+`6 chars`) and `public key` in base64 (PEM) format (`S_PK`) [reference](https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem)
19```json
20{
21 "student_id": "e123456",
22 "passwd": "15 char secret",
23 "public_key": "---BEGIN PUBLIC KEY..."
24}
25```
26
27## Cipher Initialization
28
29> Since we are working with AES-128, both key and IV should be 128 bits (or 16 hexadecimal characters)
30
31- Pick a short temporary key (`k_temp`)
32- Pick a random IV [1](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_(IV)) [2](https://en.wikipedia.org/wiki/Initialization_vector) (`iv`).
33
34## Encryption
35- Encrypt the serialized string of `P_AR` with 128 bit block [AES](https://en.wikipedia.org/wiki/Initialization_vector) in [CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CBC) mode with [Pkcs7 padding](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Padding) using the temporary key (`k_temp`), the result is `C_AR`. Encode this with base64.
36- The temporary key you have picked `k_temp` is encrypted using RSA with [OAEP](https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding) padding scheme using SHA-256 with `gradecoin_public_key`, giving us `key_ciphertext`. Encode this with base64.
37- Base64 encode the IV (`iv`) as well.
38
39{% tidbit() %}
40The available tools and libraries might warn you about how using the primitives given above are "hazardous". They are, crypto is hard.
41{% end %}
42
43- The payload JSON object (`auth_request`) can be serialized now:
44
45```json
46{
47 "c": "C_AR",
48 "iv": "iv",
49 "key": "key_ciphertext"
50}
51```
52
53If your authentication process was valid, you will be given access and your public key fingerprint that is your address.
54You can now sign [JWTs](@/JWT.md) to send authorized transaction requests.
diff --git a/content/transaction_docs.md b/content/transaction_docs.md
new file mode 100644
index 0000000..05c1534
--- /dev/null
+++ b/content/transaction_docs.md
@@ -0,0 +1,52 @@
1+++
2title = "Transactions"
3description = "Transaction documentation"
4weight = 6
5+++
6
7A transaction request between `source` and `target` to move `amount` Gradecoin.
8
9# Requests
10
11## GET
12A HTTP `GET` request to [/transaction](/transaction) endpoint will return the current list of pending transactions.
13
14## POST
15
16A HTTP `POST` request with Authorization using JWT to [/transaction](/transactions) will allow you to propose your own transactions.
17
18# Fields
19```
20by: Fingerprint
21source: Fingerprint
22target: Fingerprint
23amount: unsigned 16 bit integer
24timestamp: ISO 8601 <date>T<time>
25```
26
27# Hash
28
29`tha` field in [jwt documentation](@/JWT.md) in fact stands for "The Hash", in the case of a post request for a transaction, you need the Md5 hash of the serialized JSON representation of transaction. The resulting JSON string should look something like;
30
31```
32{"by":"foo","source":"bar","target":"baz","amount":2,"timestamp":"2021-04-18T21:49:00"}
33```
34
35Or; without any whitespace, separated with `:` and `,`.
36
37# Bank
38
39There is a `bank` account with Fingerprint `31415926535897932384626433832795028841971693993751058209749445923`
40
41{% tidbit() %}
42First 64 digits of Pi
43{% end %}
44
45This is the only account that will let you _withdraw_ from them.
46
47```
48by: this has to be your Fingerprint
49source: this can be either you or the bank
50target: this can be a valid fingerprint or yourself if source is the bank
51...
52```
diff --git a/static/android-chrome-192x192.png b/static/android-chrome-192x192.png
new file mode 100644
index 0000000..023ddbd
--- /dev/null
+++ b/static/android-chrome-192x192.png
Binary files differ
diff --git a/static/android-chrome-512x512.png b/static/android-chrome-512x512.png
new file mode 100644
index 0000000..4251933
--- /dev/null
+++ b/static/android-chrome-512x512.png
Binary files differ
diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png
new file mode 100644
index 0000000..cd8e4c8
--- /dev/null
+++ b/static/apple-touch-icon.png
Binary files differ
diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png
new file mode 100644
index 0000000..bd63d34
--- /dev/null
+++ b/static/favicon-16x16.png
Binary files differ
diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png
new file mode 100644
index 0000000..e343587
--- /dev/null
+++ b/static/favicon-32x32.png
Binary files differ
diff --git a/static/favicon.ico b/static/favicon.ico
new file mode 100644
index 0000000..45d8bfe
--- /dev/null
+++ b/static/favicon.ico
Binary files differ
diff --git a/static/gradecoin.png b/static/gradecoin.png
new file mode 100644
index 0000000..eeb670c
--- /dev/null
+++ b/static/gradecoin.png
Binary files differ
diff --git a/static/gradecoin.pub b/static/gradecoin.pub
new file mode 100644
index 0000000..ffe2f12
--- /dev/null
+++ b/static/gradecoin.pub
@@ -0,0 +1,9 @@
1-----BEGIN PUBLIC KEY-----
2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGuqiCPGcguy+Y9TH7Bl
37XlEsalyqb9bYlzpbV0dnqZ3lPkEPkuOhkN+GcuiV6iXtSwyh7nB+xTRXKJFRUBO
4/jbN8jfcxVwBu0JxjF3v1YRBxbOHhz2A295mbKD9xHQCKxkfYBNkUXxj8gd+GaDv
5QiSW5NdrX/lEkvqfGtdEX1m2+HdcG0+3YW24Xg0znhCwLr+sorLuJaDy9Xa0Uo+D
6PWGC5s001U/BxkCIWJ+eJQCb7Bv+9vXb8BGRK/ecMb/fb6h5O+8fgB64RCHMgcc2
7v+Q/dPt8kHX1OJdMuYUrUJGACppMQY3W6e1HdlRIBcZKL2LMZ2CrIB/2D5LiJhPT
8hQIDAQAB
9-----END PUBLIC KEY-----
diff --git a/static/site.css b/static/site.css
new file mode 100644
index 0000000..6c79aa9
--- /dev/null
+++ b/static/site.css
@@ -0,0 +1,57 @@
1.content blockquote {
2 border-left: #689d6a 8px solid;
3
4}
5.content blockquote.tidbit {
6 border-left: #928f74 8px solid;
7 font-size: 12px;
8 color: #282828;
9}
10
11li p {
12 margin: 2px;
13}
14
15/* OUTER CONTAINER */
16.tcontainer {
17 width: 100%;
18 overflow: hidden; /* Hide scroll bar */
19}
20
21/* MIDDLE CONTAINER */
22.ticker-wrap {
23 width: 100%;
24 padding-left: 100%; /* Push contents to right side of screen */
25 background-color: #eee;
26}
27
28/* INNER CONTAINER */
29@keyframes ticker {
30 0% { transform: translate3d(0, 0, 0); }
31 100% { transform: translate3d(-100%, 0, 0); }
32}
33
34.ticker-move {
35 /* Basically move items from right side of screen to left in infinite loop */
36 display: inline-block;
37 white-space: nowrap;
38 padding-right: 100%;
39 animation-iteration-count: infinite;
40 animation-timing-function: linear;
41 animation-name: ticker;
42 animation-duration: 30s;
43}
44
45.ticker-move:hover{
46 animation-play-state: paused; /* Pause scroll on mouse hover */
47}
48
49/* ITEMS */
50.ticker-item {
51 display: inline-block; /* Lay items in a horizontal line */
52 padding: 0 5px;
53}
54
55.ticker-item::before {
56 content: " ✑ ";
57}
diff --git a/templates/_variables.html b/templates/_variables.html
new file mode 100644
index 0000000..3fd05b4
--- /dev/null
+++ b/templates/_variables.html
@@ -0,0 +1,15 @@
1<style>
2 :root {
3 /* Primary theme color */
4 --primary-color: #F8D12F;
5 /* Primary theme text color */
6 --primary-text-color: #1E2329;
7 /* Primary theme link color */
8 --primary-link-color: #2F57F7;
9 /* Secondary color: the background body color */
10 --secondary-color: #FAFAFA;
11 --secondary-text-color: #303030;
12 /* Highlight text color of table of content */
13 --toc-highlight-text-color: #d46e13;
14 }
15</style>
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..08e3c8a
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,68 @@
1{% extends "juice/templates/index.html" %}
2
3{% block head %}
4<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
5<link rel="stylesheet" href="/site.css" />
6{% endblock head %}
7
8{% block hero %}
9
10<section class="text-center">
11 <h1 class="heading-text animate__animated animate__jackInTheBox" style="font-size: 50px">
12 Mine your own grades
13 </h1>
14 <h3 class="title-text">
15 <b>Gradecoin</b> is the latest cutting edge blockchain technology agile grading framework that drives organic engagement and other buzzwords, with big data mining search engine optimization
16 </h3>
17 <div>
18 </div>
19</section>
20<img class="hero-image" style="width: 40%" src="{{ get_url(path="gradecoin.png") }}">
21
22<div class="explore-more text"
23 onclick="document.getElementById('features').scrollIntoView({behavior: 'smooth'})">
24 ⇩ Learn How ⇩
25</div>
26
27<style>
28
29.hero section {
30 padding: 0 5rem;
31}
32
33@media screen and (max-width: 768px) {
34 .hero section {
35 padding: 0 2rem;
36 }
37
38 .hero-image {
39 display: none
40 }
41
42}
43footer {
44 color: #8b8b8b;
45}
46</style>
47{% endblock hero %}
48
49{% block content %}
50<div class="tcontainer" id="features">
51 <div class="ticker-wrap">
52 <div class="ticker-move">
53 <div class="ticker-item"><b>News:</b></div>
54 <div class="ticker-item">Gradecoin is in testnet mode, API is not stable, everything might reset at any time.</div>
55 <div class="ticker-item">Transactions are now unique according to their "by" field, sorry for the trouble</div>
56 <div class="ticker-item">Blocks now require 5 transactions in them, during testnet phase</div>
57 <div class="ticker-item">It was possible (and hilarious) to mine a new block with just 1 transaction, it is now fixed</div>
58 </div>
59 </div>
60</div>
61{{ section.content | safe }}
62{% endblock content %}
63
64{% block footer %}
65<footer>
66Built For ⁂ CENG489 ⁂ Introduction to Computer Security
67</footer>
68{% endblock footer %}
diff --git a/templates/shortcodes/exp.html b/templates/shortcodes/exp.html
new file mode 100644
index 0000000..5a37a39
--- /dev/null
+++ b/templates/shortcodes/exp.html
@@ -0,0 +1 @@
{{ num }}<sup>{{ exponent }}</sup>
diff --git a/templates/shortcodes/tidbit.html b/templates/shortcodes/tidbit.html
new file mode 100644
index 0000000..7023578
--- /dev/null
+++ b/templates/shortcodes/tidbit.html
@@ -0,0 +1,5 @@
1<blockquote class="tidbit">
2 <p>
3 {{ body }}
4 </p>
5</blockquote>