This page is a review of elementary cryptographic operations and introduces a simple cryptocurrency managed by a trusted agent.
The next module discusses the algorithm underlying Bitcoin; the Bitcoin algorithm doesn't require agents to be trusted. This Princeton University book is a superb description of Bitcoin.Let's look at the following problem: Given \(H\), find any colliding pair \(x, y\).
Consider a hash function \(H\) that outputs \(n\)-bit numbers and whose input is \(m\) bit strings. As a specific example lets assume that \(m\) is a large number and \(n = 4\). We can find a collision in the following way.
Let \(D\) be an array of size \(2^{n} = 16\). Initially \(D\) contains null values. Repeat the following iteration until a collision is found. Pick a random input \(x\). If \(D[H(x)]\) is null then set \(D[H(x)] = x\) else there is a collision between \(H(x)\) and \(x\).
By the pigeon-hole principle, we will find a collision in at most \(2^{n} + 1 = 17\) iterations. This brute-force algorithm uses space \(2^{n}\) and finds a collision in at most \(2^{n} + 1\) steps. From the Birthday Paradox a collision will be found with high probability in \(2^{n/2}\) iterations though the worse-case time is \(2^{n}+1\). If \(n = 256\) then a collision will be found with high probability in \(2^{128}\) iterations; however, executing \(2^{128}\) steps is still intractable.
For \(H\) to be collision resistant the output of \(H\) must be \(n\)-bits for large \(n\). For example \(n = 256\) in the SHA-256 hash function.
The trusted third party provides two services:
Can we use a hash function instead of a trusted third party?
Does the hash function provide the services of the third party? Can you discover Megan's prediction before she reveals it?
It's easy. There are only 32 teams playing. Compute \(H(x)\) where \(x\) runs over each of the 32 teams. One of those teams has to be \(W\). You can discover her prediction in at most 210 steps.
Let's try another algorithm. Megan selects a secret value \(r\) which she keeps to herself. Instead of giving you \(H(W)\), she gives you \(y\) where \(y = H(r + W)\) and where \(+\) indicates concatenation of strings. Can you discover \(W\) from \(H\) and \(y\) without knowing \(r\)?
A brute-force solution is to try every combination of \(r\) and \(W\). If \(r\) is obtained from a distribution that is spread out, then finding \(W\) without knowing \(r\) take so much time that it is practically impossible.
Does the hash function \(H\) and the secret \(r\) provide both services of the trusted third party? Is Megan bound to her prediction or can she change her "prediction" after knowing the winner of the World Cup?
Suppose Megan has values \(r\) and \(r'\) such that H(r + 'Brazil') = H(r' + 'Italy'). After the World Cup is over, she can announce that her secret is \(r\) if Brazil wins, and announce that it is \(r'\) if Italy wins.
Suppose you give Megan a hash function that is binding. Then she cannot find (in reasonable time) values \(r_{j}\) to match country \(C_{j}\) such that
\(H(r_{0} + C_{0}) = H(r_{1} + C_{1}) = H(r_{2} + C_{2}) = \ldots\).
and so she can't wait for the winner \(C_{j}\) to be announced before announcing her secret \(r_{j}\).
In summary, we can use a hash function that is hiding and binding to play the role of a trusted third party in a commitment.
In this problem, as opposed to the hiding problem, we are given \(r\) and not \(x\),
The hash function \(H\) is said to be puzzle friendly exactly when any algorithm to solve this problem is about as slow as a brute-force algorithm which checks \(H(r+x) = y\) for random values of \(x\). The number of steps taken by any algorithm that solves this problem is not significantly lower than \(2^{n}\).
Now, let's look at the following related problem. Given \(H\), \(r\), and a set \(Y\) of \(n\)-bit strings, compute any \(x\) such that \(H(r+x) \in Y\). If \(Y\) consists of a single element \(y\) then this problem is the same as that in the previous paragraph. If \(Y\) is a set of all \(n\)-bit strings then this problem is trivial because any \(x\) solves the problem. The probability that a random value hashes to an element of \(Y\) is proportional to the cardinality of \(Y\). The cardinality of \(Y\) controls the expected time to solve the puzzle.
We can use function \(f\) to define a function \(g\) whose inputs are strings of arbitrary
lengths and whose outputs are strings of length \(M\).
Example code for \(g\) is given below where InitialValue
is a given constant string of length \(M\).
def g(y): output = InitialValue // pad y so that it's length is a multiple of N if len(y)%N > 0: y = y + "0"*(N - len(y)%N) // partition y into blocks of size N blocks = [y[i: i+N] for i in range(0, len(y), N)] // Apply function f to the concatenation of the // previous output (length M) with each block // (length N) to get the next output (length M). for block in blocks: output = f(output+block) return output
Single Block
A simple example of a tamper-evident structure is a single block of data D which is pointed to by a hash pointer consisting of a regular pointer and a hash H(D). Assume that a malicious agent cannot modify both the hash pointer and the data that it points to. If an agent changes D to D' then the tampering can be discovered because the hash pointer won't match the data that it is pointing to: \(H(D') \neq H(D)\).The \(j\)-th element of the list, \(j > 0\), consists of data, \(D_{j}\), and a hash pointer that points to the \(j - 1\)-th element of the list. The hash pointer in the \(j\)-th element consists of a regular pointer, \(ptr_{j}\), which points to the \(j - 1\)-th element of the list, and a hashed value, \(HA_{j}\), which is a cryptographic hash of the entire \(j-1\)th element consisting of \(D_{j-1}\), \(ptr_{j-1}\) and \(HA_{j-1}\). The \(0\)-th element is called the genesis element and has default values. The list is accessed by a hash pointer that points to the last element of the list; let this pointer be \(ptr_{n}, HA_{n}\).
Assume that agents cannot modify \(ptr_{n}, HA_{n}\). Then, can any agent determine whether the list has been tampered with?
Suppose the agent modifies \(D_{j}\), \(ptr_{j}\) or \(HA_{j}\) for any \(j < n\). Any agent can detect this tampering because the hash value \(HA_{j+1}\) will no longer match the \(j\)-th element of the list. If the malicious agent also modifies \(HA_{j+1}\) then hash value \(HA_{j+2}\) will no longer match the \(j+1\)-th element.
By induction on \(j\), any agent can detect tampering with the list provided malicious agents do not also modify the hash pointer to the last element of the last.
A Merkle tree is a special case of a binary balanced tree in which data items are stored only in the leaves. Nodes that are not leaves contain only hash pointers to nodes in the next level down. To prove that an element at the leaf is a member of the tree we need only the \(log_{2}(n)\) hash pointers on the path from the root to that leaf. By contrast, to prove that an element is a member of a linear list we need to inspect \(O(n)\) elements, on average.
Sending messages securely
Keys are used to send messages securely. Kamala sends a secure message to Joe by encrypting the message with Joe's public key; Joe decrypts the message using Joe's private key. An agent cannot decrypt the encrypted message without Joe's private key.Signing messages
Suppose Kamala needs to send a signed message to Joe while ensuring that nobody can forge her signature. She encrypts the message M with her private key to get an encrypted message M', and sends the pair (M, M') securely to Joe, i.e., she encrypts (M, M') with Joe's public key, and sends the resulting encrypted message to Joe. When Joe receives the message, Joe decrypts it using his private key to get (M, M'). Then Joe decrypts M' using Kamala's public key to get the decrypted message M''. If M'' = M then Joe knows that Kamala sent M because only an agent with Kamala's private signature could have sent that message.L
of transactions that we call a
tamper-evident ledger.
Any agent can get a copy of the ledger.
This tamper-evident ledger is the foundation of the currency.
A transaction is one of two types: create or pay. In a pay transaction, payers give coins that they possess to payees. An agent can be both a payer and payee of the same transaction. In a create transaction the bank creates coins that it gives to agents --- the payees of the transaction; the bank acts as the payer.
For this system to be trusted the bank must follow some protocol that determines how and when the bank creates coins. We won't discuss these protocols.
A pay transaction is signed by all payers of the transaction. A create transaction is signed by the bank. We discussed digital signatures and keys earlier.
Each element of the tamper-evident ledger has:
(value, payee public key)
, where each
pair in the array indicates that coins of the specified value are
given to the payee with the specified public key.
(3146, create, [(2.1, 7xxxx...), (3.2, 8xxxx)]).The id of this transaction is 3146, the type of the transaction is create, and the array of value-payee pairs is
[(2.1, 7xxxx...), (3.2, 8xxx)]In this transaction the bank creates a coin of value 2.1 and gives it to the agent with public key 7xxxx..., and the bank also creates a coin of value 3.2 and gives it to the agent with public key 8xxxx...
The pair:
(transaction id, index into array of value-payee pairs)uniquely identifies a (value, payee) tuple.
For example (3146, 0) --- transaction id 3146, and array index 0 --- identifies value-payee[0] of transaction 3146 which is specified by the 2-tuple: (2.1, 7xxxx...). So, the transaction id and index, (3146, 0), tells everybody that the agent with public key 7xxxx received 2.1 units of coin in transaction 3146.
When this transaction is in a tamper-evident ledger, every agent from that point onwards knows that agent 7xxxx received 2.1 coins. Any modifications of this record can be detected.
Likewise, (3146, 1) --- transaction id 3146, and array index 1 --- identifies value-payee[1] which is the 2-tuple (3.2, 8xxxx...).
(transaction id, index into array of value-payee pairs)where
transaction id
is the id of the transaction in the
tamper-evident ledger. As we said earlier, this pair uniquely identifies an agent and a
value that this agent acquired in this transaction.
For example the pair --- transaction id, index --- such as (3146, 0)
identifies the 2-tuple (2.1, 7xxxx...); this 2-tuple asserts
that the agent
with public key 7xxxx received 2.1 units of coin in
transaction 3146. The entire amount specified in the 2-tuple (2.1 in our
example) is value that flows into this pay transaction from the agent
with public key 7xxxx.
Suppose the payers in a pay transaction are identified by the list:
[(3146, 0), (7359, 3)]and suppose pair 3 in transaction 7359 is (3.2, 8xxxx). Then the total amount of coins flowing into this pay transaction is 2.1 + 3.2, and this amount is disbursed to payees.
The system may provide incentives, such as payment of coins, to managers (e.g. banks) of cryptocurrencies. In this case, one of the payees is the bank itself.
To put in more value, the bank identifies other transaction-id, index pairs in which this agent received coins. For example, say that (4539, 2) identifies a 2-tuple (3.2, 7xxxx), and assume that the payers in this transaction are specified by the pairs (3146, 0) and (4539, 2). The pair (3146, 0) asserts that agent (7xxxx) received 2.1 coins and the pair (4539, 2) asserts that the same agent received 3.2 coins. So the total amount of coins flowing into this transaction from this agent (7xxxx) includes 2.1 + 3.2.
To put in less value, the agent acts as both payer and payee; the net value that this agent pays out to other agents is the difference between the amount that this agent puts in and takes out. For example, if agent with public key 7xxxx wants to put in 1.9 coins into this transaction its payer information can be given by the transaction-id, index pair (3146, 0) which asserts that the agent received 2.1 coins and the same agent is a payee that withdraws 0.2 coins.
For example, the transaction id, index pair (3146, 0) identifies the 2-tuple (2.1, 7xxxx...); this tuple asserts that the agent with public key 7xxxx received 2.1 units of coin in transaction 3146. Why can't the agent with public key 7xxxx use the 2.1 coins that it received to buy items from Amazon and later use the same 2.1 coins to buy more items from Walmart?
The bank checks that the agent hasn't already spent the coin that it is putting into a transaction.
Before permitting the transaction that double-spends the 2.1 coins with Walmart, the bank inspects the tamper-evident ledger for all transactions after transaction 3146 and before the Walmart transaction to ensure that the agent (7xxxx) hasn't already spent the 2.1 coins that it got in transaction 3146. The transaction that spends the coins at Amazon will show up in the ledger, and so the transaction with Walmart will not be allowed.
Every agent that has the bank's hash pointer to the end of the tamper-evident ledger can inspect the ledger to check that double-spending hasn't occurred.
The bank signs a valid transaction and appends it to the tamper-evident ledger. All agents can see the bank's signature and verify that nobody (not even the bank) has tampered with the tamper-evident ledger.
(9431, pay, [(3146, 0), (4731, 2)], [(0.7, 7xxxx...), (4.6, 9xxxx...)] ).The id of this transaction is 9431; the type of the transaction is pay; the payers into the transaction are identified by the pairs of (transaction-id, index): (3146, 0), and (4731, 2); and the payee array is [(0.7, 7xxxx...), (4.6, 9xxxx...)].
L
if and only if the
transaction is valid. The bank checks for validity by carrying out the
following steps:
The amount of computation decreases as the number of transactions in a block increases. The time required to fill a block with transactions is larger when the number of transactions to fill the block increases.
An old copy of the ledger can differ from the current copy in only one way: the current copy may have transactions appended to the end of the old copy. So all agents can validate past behavior of the trusted agent. An agent cannot, however, treat its copy of the ledger as the master copy because the agent may not have the transactions added most recently to the ledger.
In the next module we will see how the Bitcoin algorithm addresses this problem.
The bank can't forge a transaction because all payers sign the transaction. Agents can remain anonymous because an agent's only public information is the agent's public key, and an agent can create multiple public keys. Every agent can verify the correctness of every transaction.
Next we'll look at Bitcoin's algorithms for implementing a cryptocurrency without trusted agents.
K. Mani Chandy, Emeritus Simon Ramo Professor, California Institute of Technology