# Blockchain Developer Foundations Useful background: * Basic computer science & data structures * Number theory: [modular arithmetic](https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic) ## What is hashing? **Hashes** are data produced by a **hash function**. A hash function takes any data as input, called the **preimage**, and produces some output, called the **image** or the hash. Hashes have these properties: * The same preimage always produces the same image. In other words, hash functions are pure functions[^pure-function]. * A hash acts as a fixed-sized fingerprint of its image. [^pure-function]: https://en.wikipedia.org/wiki/Pure_function For example, a hash function over variable-length text strings may be defined as follows: ```python def my_hash_function(s: str): return len(s) ``` This hash function simply outputs the length of the string. Now, this is a perfectly valid hash function, but it might not be useful in very many contexts. Because hash functions give us a "fingerprint" of some data, typically, we also want hash functions to have very few **collisions**, that is very few instances where different preimages produce the same image. ```python my_hash_function("hello") != my_hash_function("h") # no collision my_hash_function("hello") == my_hash_function("world") # collision! ``` For purposes of cryptography, we also want hash functions to be one-way and avalanching. ### One-way functions A **one-way** function produces an image from which it is extremely difficult or impossible to derive the preimage, and ideally, any information about the preimage whatsoever. This means that our hash function above is a one-way function (since it is nearly impossible to determine the original input if all you know is the length of that input was 5). However, a function that returned the index of a word in a dictionary would not be a good one-way function, since it is possible to determine the original word given its index in the dictionary. ### Avalanching functions The output of an **avalanching** function changes drastically in response to a small change in its input. You might think of this like the "butterfly effect," except over function outputs instead of over time. A function probably exhibits a strong avalanching effect if every bit of the output depends on every bit of the input. Our hash function above does not exhibit strong avalanching: changing one letter of the input may not change the output at all! However, a phenomenon that has a lot of inherent chaos or complexity may be a good candidate: imagine if the input data were used to seed starting conditions for a [double pendulum system](https://en.wikipedia.org/wiki/Double_pendulum)? ### Real cryptographic hash functions * [SHA family](https://en.wikipedia.org/wiki/Secure_Hash_Algorithms) * [BLAKE family](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) ## What is asymmetric-key cryptography? Since "asymmetric" means "not symmetric," it may be useful to start with a definition of symmetric-key cryptography first. ### Symmetric cryptography A cryptographic scheme is called **symmetric** if the same **key** (i.e. password) that was used to encrypt data can be used to decrypt the encrypted data. Imagine you wanted to send your friend a sensitive PDF file. To make sure that nobody else can read the file, you password-protect the PDF file and email it to him. Then you call your friend on the phone and tell him the password. Now your friend is able to use that password to unlock the PDF file and read the contents. This is an example of a symmetric encryption scheme: the password you used to encrypt the file is the same one your friend used to decrypt it. ### Asymmetric cryptography Now, what about *a*symmetric cryptographic schemes? As one might expect, a cryptographic scheme is considered **asymmetric** if the encryption process uses a *different* key than the decryption process. This might be a confusing idea: that the key one uses to "lock" something is not also the key one uses to "unlock" that same thing. ### Asymmetric operations Let's look at a few examples of asymmetric schemes. Imagine our encryption/decryption operation is multiplication. If our original data is `42`, we could "encrypt" it using a key `5` to get the "ciphertext" `210`. Our decryption key in this case would be `0.2`, which, when applied to (multiplied by) the ciphertext reveals the original data. `0.2` is called the **multiplicative inverse** of `5`. A slightly more complex example: When performing computations in **modular arithmetic**[^modular-arithmetic], the result of a computation is delivered "mod m," where `m` is the **modulus**. [^modular-arithmetic]: https://en.wikipedia.org/wiki/Modular_arithmetic One everyday example of modular arithmetic is the 12-hour clock. If it is 11 o'clock and you ask: "What time will it be in 3 hours?", you're asking for the answer to this expression: `11 + 3 (mod 12)`, which is `2`. Floating point (i.e. fractional) numbers don't make as much sense in a modular arithmetic context, so the multiplicative inverse of a number `x (mod m)` is defined as the number `i` which, when multiplied by`x (mod m)` is `1`. For example, the multiplicative inverse of `5 (mod 7)` is `3`.[^inverse-5-7] [^inverse-5-7]: https://www.wolframalpha.com/input?i=multiplicative+inverse+of+5+mod+7 This means if we use the key `5 (mod 7)`, the encryption process will look like this, where `4` is our original data: ```txt 4 * 5 (mod 7) = 6 ``` So `6` is our ciphertext. To decrypt our ciphertext, we multiply it by our key's multiplicative inverse (`3`): ```txt 6 * 3 (mod 7) = 4 ``` And we get `4`, which was our original data. ### Practical asymmetric cryptography We've established that asymmetric-key cryptographic schemes use different keys for encryption and decryption. Modern cryptography distinguishes the two keys in the **keypair**: the **private key** and the **public key**. The private key is intended to be safeguarded by the owner of the keypair, whereas the public key is meant to be distributed. The public key can be derived from the private key, but not the other way around. Both the public and private keys can be used to encrypt messages, and only the complementing key can decrypt the resulting ciphertext. These properties allow users to do some useful things: * If a message is encrypted with a public key, *only the corresponding private key* can decrypt it. This allows for anyone to send a private message to the owner of a keypair. * If a message is encrypted with a private key, *only the corresponding public key* can decrypt it. Since everyone has access to the public key, this allows someone to prove that they are the owner of a keypair without revealing the private key. This process (encryption with a private key) is usually called **signing**. The public key is sometimes called the **verify key**, and the private key the **secret key**. ## What is a distributed system? Blockchain-based cryptocurrencies really like things to be "distributed," but what does that really mean? A distributed system is one comprised of distinct **nodes** networked together and synchronized with each other. Essentially, it's a bunch of computers talking to each other over the Internet. However, we also like to throw a wrench in things and make our systems **decentralized** as well. This means that there is no central authority telling any of the nodes what to do. This is different from how most services on the Internet work. Most Internet services have a server, which acts as the single source of truth, telling all of its clients what to do. This is a convenient infrastructure for most web services because it eliminates any possibility for the client to argue with the server; it simply accepts whatever it is delivered. If a network is decentralized, that means that the participants in the network must establish some way of agreeing with each other, or reaching **consensus**. However, this is a particularly difficult problem! Imagine a node in a decentralized network wanted to ask the network what the current time is. The querying node could conceivably receive a different answer from every node on the network, simply due to different nodes having slight variations in their local clocks or due to network latency. This is not even taking into account the possibility that some of the nodes on the network might *lie*, and we're already running into issues! We want to maintain decentralization because a decentralized network is a robust network: there's no single point of failure, and it's impossible to shut down or censor. Therefore, decentralized distributed systems must have some protocol for reaching consensus with each other that avoids issues of indetermination (e.g. network latency, etc.) and is also robust agains malicious actors. ## What is trustlessness? In our distributed network, nodes might leave or join at any time. When a node joins, there's no way for anyone to know for certain whether that node will act honestly or dishonestly, and there's no-one to tell us whether we should trust a node. This might make it seem like it would be useful to have some sort of authority that can simply tell us this, but that would violate the decentalization of the network. Therefore, instead of implicitly trusting any of the nodes connected to the network, we'll simply trust the network protocol. This idea of "not implicitly trusting network nodes" is called **trustlessness**, and it's central to the value proposition of decentralized cryptocurrencies, who are essentially saying: "Instead of trusting us or anyone connected to our network, trust in yourself and the network *protocol*." Of course, trusted (i.e. not trustless) systems absolutely have their time and place as well: most websites, governments, banks, companies, etc. are all dependent on certain concentrations of authority, which is derived from trust. In fact, trusted systems are usually faster and more efficient than trustless ones, but they don't provide the same guarantess. Like most things in life, it's a trade-off. ### Case study: identity Who owns your Internet identity? Well, if you use Google services (e.g. "log in with Google", GMail, Google Chrome password management) then Google owns that part of your online identity. "Log in with Facebook"? Facebook owns and manages your identity. "Log in with Twitter"? Twitter owns and manages your identity. "Log in with your email"? Your email provider owns and manages your identity. Whenever you log in with a service managed by a third party, that third party has control over that part of your online identity. What about "Log in with your cryptographic key"? Who owns your keypair? You do! You're *trusting nobody but yourself* with the management of your identity in this case, and this is a great demonstration of the power of trustless systems. ## What is a blockchain? A blockchain may be thought of as a variation of a linked list, wherein the first node (**genesis node** or **genesis block**) is "pointed to by" the second node, which is "pointed to by" the third node, and so on and so forth. That is to say, each node points to its parent as opposed to its successor (as is typical in a normal linked list). The blockchain maintains and updates a conglomerate state[^state]. **Actors** participating in the blockchain may execute certain updates to the state. Generally, actors are allocated a portion of the available state which they are allowed to manage and modify as they see fit, in accordance with the rules of the blockchain protocol. [^state]: https://www.freecodecamp.org/news/state-machines-basics-of-computer-science-d42855debc66/ There are two types of actors: external and internal. An external actor would be something like a person or process that exists outside the blockchain and performs some interactions with the blockchain. Internal actors exist as a part of the very blockchain itself. Typically, only external actors are allowed to unilaterally initiate interactions with the blockchain, and internal actors can only respond to interactions another actor initiated. Updates to the state are represented by structures called **transactions**. When an actor wishes to modify some state, it issues a transaction to the blockchain which performs that change. Transactions (that is, updates to state) are ordered and inserted into collections called **blocks**. A block contains all of the transactions that occured during a specific time range. For example, a block may contain all of the transactions that occurred in a particular 10-minute timespan. Blocks in a particular blockchain usually span consistent durations, so the length of time a block represents is called the **block time**. Once all of the transactions that occurred in a certain duration have been collected into a block, that block is added onto the end of the blockchain, thus creating a "chain" of blocks. The blockchain synchronizes state across a distributed system. This solves the data synchronization problem, but we still have the consensus problem. ### Reaching consensus Blockchain-based cryptocurrencies use a system called a **consensus mechanism** to facilitate agreement across the decentralized network. These mechanisms involve a node offering some proof to the network that it will be honest. * Proof-of-Work networks solve complex mathematical problems, sacrificing time, electricity, and hardware longevity as evidence of their honest and commitment to the network. * Proof-of-Stake networks allow nodes to **stake** cryptocurrency tokens they already own as collateral for their honesty. If a node is dishonest, their collateral is forfeit. ## What is a smart contract? A **smart contract** is an autonomous, internal, on-chain actor. It's some logic that has been deployed to the blockchain and manages a portion of the blockchain state in accordance with the dictates of its logic. Smart contracts have a number of advantages over traditional computer programs: * Every action a smart contract performs is cryptographically proven. * Since every interaction involving a smart contract occurs on a public blockchain, there is a high degree of transparency regarding the internal workings of the logic. * Smart contracts are guaranteed to abide strictly by their deployed logic, meaning that smart contract interactions are trustless. * Smart contracts are executed as part of transaction resolution. A smart contract's uptime is therefore equal to that of its host network! However, smart contracts are not the be-all, end-all of web applications. They come with a significant number of limitations: * Public * Expensive * Slow * Immutable * Non-upgradable * Difficult to index * Non-scheduling * Deterministic * Non-networked Some of these limitations are partially addressed in some way by different blockchain projects, but this is a generally true list. It's important to understand that smart contracts are not a silver bullet that represent the ultimate, inevitable future of web applications. Rather, smart contracts are a new tool that can be used to provide new guarantees about Internet applications that were previously difficult or impossible. # Author Jacob Lindahl • Software Engineer, [Pagoda](https://www.pagoda.co/) • [@sudo_build](https://twitter.com/sudo_build) • <jacob.lindahl@near.org>