The Mathematics of Digital Cash
Joey Yandle
2018-12-23
While traditional cryptocurrencies were groundbreaking in many ways, they lacked the privacy protections
that cash inherently provides. This document will explore the math which can provide some of those protections.
The goal is to build a cryptocurrency which deserves the name Digital Cash.
There are many papers which outline, define, use, mutate, expand on, or cite the following techniques. But
these papers invariably use different terminology, swapping variable names and using various subsets as needed.
In this document, I will endeavor to be both thorough and strongly consistent, which should not only make the
math easier to understand, but also expose the deep connections and demonstrate how each piece builds on the
previous.
1
1 Notation
We define a hash function H
n
as a function that maps an unbounded list of arbitrarily-sized binary inputs to
an output set O of n bits:
H
n
:
= { i
1
, i
2
, ... | b {0, 1}, k N, i b
1
b
2
...b
k
} 7→ { b
1
b
2
...b
n
| b {0, 1} }
If we do not define n, then we assume it is implementation dependent, but that the output set is still bounded
at some n bits:
H
:
= { i
1
, i
2
, ... | b {0, 1}, k N, i b
1
b
2
...b
k
} 7→ { b
1
b
2
...b
n
| b {0, 1} }
2 Schnorr Proofs and the Fiat Shamir Transform
Schnorr proofs [1] allow the owner of a private key to demonstrate that ownership to someone who knows
the corresponding public key. It is an interactive 3-move protocol, i.e. a Sigma protocol. But like all Sigma
protocols, it can be made non-interactive using the Fiat-Shamir transform [2]. This allows the protocol to
function as a signature.
Let g be a generator in a finite group G of prime order p P, with private key x Z
p
, and public key
y = g
x
. The prover chooses a random v Z
p
, then sets t = g
v
.
In the interactive version of the protocol, the prover sends t to the verifier, who responds with the challenge
c. This way the prover cannot choose t after seeing c, which would allow the prover to cheat. To make this
non-interactive, Fiat and Shamir proposed to choose c based on a hash including t, which prevents the prover
from cheating, since c depends on t:
c = H(g, y, t) (1)
The prover then defines r as below, and calculates it from (v, c, x):
r = v cx (2)
This is equivalent algebraically to
v = r + cx
We can use this derived expression for v to expand t:
t = g
v
= g
r+cx
= g
r
g
cx
= g
r
g
xc
= g
r
(g
x
)
c
= g
r
y
c
(3)
So if t = g
r
y
c
, then the prover must have known x. Otherwise the prover would not have been able to
construct a proper r, allowing the equation to balance. The set (r, c, t) thus forms the proof of ownership of y.
3 Ring signatures
A Schnorr proof allows us to sign a public key, proving we know the corresponding private key. But the signature
is tied to a single key, which is bad for privacy. It would be better to construct a one out of many signature, to
prove that we knew the private key for one out of N public keys. Such a signature is called a ring signature [3].
Start with public key y for which the prover knows the private key x, and as before, choose a random v Z
p
. To mix in an additional key y
1
whose private key x
1
is unknown, select a random r
1
and c
1
. The prover sets
c as follows, using the values known to calculate it:
c = H(g
v
, g
r
1
y
c
1
) c
1
(4)
This is equivalent algebraically to:
c + c
1
= H(g
v
, g
r
1
y
c
1
)
Now that the prover has c, r is as before:
r = v cx (5)
The prover then sends (y, r, c, y
1
, r
1
, c
1
) to the verifier, who then calculates the hash
H(g
r
y
c
, g
r
1
y
c
1
1
)
2
Since g
v
= g
r
y
c
, the two hashes are identical. Thus
c + c
1
= H(g
r
y
c
, g
r
1
y
c
1
1
) (6)
So if
P
c is equal to the hash, then the prover must have known x for some y. And since the prover can put
the real (y, r, c) in either position, there is no way for the verifier to know which key was actually signed.
We can do the same for any number of additional public keys y
k
: choose a random (r
k
, c
k
) which is added
to the hash in the form of g
r
k
y
c
k
k
then subtracting the new c
k
from the hash to form the real c. Then
P
c will
be equal to the hash for both prover and verifier.
3.1 Linkable Ring Signatures
Now that we can use ring signatures to hide which public key is being signed, we have a new problem: assuming
each public key corresponds to a spendable output, how do we know which output was actually spent? We need
a way to track this to prevent double spends, but in such a way that we preserve the privacy which the ring
signature grants.
First we construct a key image [3], which is a commitment to the public key used but cannot be used to find
the public or private keys, and is unique:
I = H(y)
x
(7)
We then add a term to the hash for each y that uses the key image. For the real y, we know that
H(y)
v
= H(y)
r
H(y)
cx
= H(y)
r
(H(y)
x
)
c
= H(y)
r
I
c
(8)
Putting the real y first, the prover hash becomes:
H(g
v
, H(y)
v
, g
r
1
y
c
1
, H(y
1
)
r
1
I
c
1
) (9)
We define c as before, then solve for the hash:
c = H(g
v
, H(y)
v
, g
r
1
y
c
1
, H(y
1
)
r
1
I
c
1
) c
1
(10)
c
1
+ c = H(g
v
, H(y)
v
, g
r
1
y
c
1
, H(y
1
)
r
1
I
c
1
)
So as before,
P
c is equal to the hash. The prover now sends (I, y, r, c, y
1
, r
1
, c
1
) to the verifier, who can
check that their hash is still equal to
P
c:
c + c
1
= H(g
r
y
c
, H(y)
r
I
c
, g
r
1
y
c
1
, H(y)
r
1
I
c
1
) (11)
Since the key image I is now tied to the signature, any attempt to sign two different ring signatures with
the same y will result in the same I, so preventing double spends is easy. You just keep track of which key
images have previously been used, and reject any new signatures with a previously used I.
3.2 Linkable Spontaneous Anonymous Group Signatures
Linkable ring signatures do a good job of proving ownership while obscuring origins, but they get large as the
number of mixins rises. LSAG signatures address this by constructing the c terms via an iterative process, so
it is only necessary to send one of them. For a large ring, this results in nearly 33% space savings.
Consider a set of public keys y
i
, i {0, , n1} with a secret index j which denotes the public key to which we
know the corresponding private key x. As before, choose random v, and r
i
i 6= j. As with linkable signatures,
define I = H(y
j
)
x
. Then define
L
j
= g
v
(12)
R
j
= H(y
j
)
v
(13)
c
j+1
= H(L
j
, R
j
) (14)
For the remaining i {j + 1, , n, , j 1} ( mod n so n goes to zero, then back to j)
L
i
= g
r
i
y
i
c
i
(15)
R
i
= H(y
i
)
r
i
I
c
i
(16)
c
i+1
= H(L
i
, R
i
) (17)
...
c
j
= H(L
j1
, R
j1
) (18)
3
Now that we have c
j
, we can define
r
j
= v c
j
x (19)
Then we can calculate L
j
and R
j
as we did for all L
i
and R
i
, using r
j
and c
j
, and the values should be equal
to the original L
j
and R
j
calculated using v. The prover now sends (I, y
0
, r
0
, , y
n1
, r
n1
, c
0
) to the verifier.
The verifier can reconstruct all (c
i
, L
i
, R
i
) and then check that c
0
= c
n
.
3.3 Multilayered LSAG Signatures
LSAG signatures allow a compact representation of a linked ring signature, but each real key needs its own
signature, and there is no way to associate the real keys with interleaved data.
The MLSAG solves this by using key vectors rather than single keys [4]. So key y
i
is instead a vector of m
keys
y
i
= (y
i,0
, ..., y
i,m1
) (20)
As before, there exists a secret index j, for which we know the private keys to each public key. Each r
i
is
now also a vector, and
r
i
= (r
i,0
, ..., r
i,m1
) (21)
i 6= j, r
i
consists of random numbers.
The prover proceeds as with an LSAG, starting with index j. v is now a vector of m elements. The L
j,k
and
R
j,k
entries are calculated in the same way, but using y
j,k
and v
k
. c
j+1
is calculated using all L
j,k
and R
j,k
:
L
j,k
= g
v
k
(22)
R
j,k
= H(y
j,k
)
v
k
(23)
c
j+1
= H(L
j,0
, R
j,0
, ..., L
j,m1
, R
j,m1
) (24)
As before, the prover calculates the remaining L
i
and R
i
using the corresponding c
i
, r
i
, and I, and the hash
for c
i+1
contains the full set of L
i,k
and R
i,k
:
L
i,k
= g
r
i,k
y
c
i
i,k
(25)
R
i,k
= H(y
i
)
r
i,k
I
c
i
(26)
c
i+1
= H(L
i,0
, R
i,0
, ..., L
i,m1
, R
i,m1
) (27)
... (28)
c
j
= H(L
j1,0
, R
j1,0
, ..., L
j1,m1
, R
j1,m1
) (29)
Now that we have c
j
, we can calculate the r
j,k
as before:
r
j,k
= v
k
c
j
x
k
(30)
The prover sends the same set of (I, y
0
, r
0
, ..., y
m1
, r
m1
, c
0
) as for LSAG, but each y
i
and r
i
is now a
vector. The verifier again calculates the full set of c
i
, with corresponding L
i
and R
i
, and checks that c
0
= c
n
.
3.4 Signing external data
Schnorr proofs and ring signatures do a good job of signing public keys, with a variety of options for obfuscating
mixins and consolidating space. But it is often desirable to sign external data, such as a transaction body. This
way the signature validates not only ownership of the inputs, but also locks the signature to the spent outputs,
amounts, or any other metadata which is necessary to prevent transaction malleability.
To sign external data d, take a hash of it then prepend it to the signature hash. But hashing the external data
directly can lead to collisions, which obviates the point of hashing. So it is common to use domain separators
in the hash:
m = H(”transaction body”, d) (31)
For a standard linkable ring signature, the prover would do the following:
c + c1 = H(m, g
v
, H(y)
v
, g
r
1
y
c
1
, H(y)
r
1
I
c
1
) (32)
The verifier also has access to the external data, and does the same calculation:
m = H(”transaction body”, d) (33)
c + c1 = H(m, g
r
y
c
, H(y)
r
I
c
, g
r
1
y
c
1
, H(y)
r
1
I
c
1
) (34)
This links the signature to the external data, and if the data is altered the verifier signature will fail validation.
4
4 Confidential Transactions
Using linkable ring signatures, we can obscure (but not hide) the real inputs to a transaction. However, the
amounts of each input must be visible in order to show that the transaction does not generate free coins: the
sum of the inputs must equal the sum of the outputs. How can we hide the actual amounts, while keeping the
ability to check that the transaction is balanced?
4.1 Pedersen Commitments
We can again use the difficulty of solving discrete logarithms to hide the real amounts behind a commitment.
The naive approach would be to simply raise our group generator g to the value v:
C = g
v
(35)
Then we can check that the sum of the input values is equal to the sum of the outputs:
v
i
1
+ v
i
2
= v
o
1
+ v
o
2
(36)
g
v
i
1
+v
i
2
= g
v
o
1
+v
o
2
(37)
g
v
i
1
g
v
i
2
= g
v
o
1
g
v
o
2
(38)
C
i
1
C
i
2
= C
o
1
C
o
2
(39)
So to check that the transaction is balanced, we check the product of the input commitments against the
product of the output commitments: if they are equal, then the transaction is balanced.
This simple approach does not work, however, because the range of values in a cryptocurrency is usually
only [0, 2
64
). So an attacker can brute force any commitment by trying all 2
64
possible values. To prevent this,
we add a random blinding factor s to the commitment [4]:
C = g
s
h
v
(40)
This requires another generator h, which is usually defined as a hash-to-group of the generator g. If the
group is a prime order group, then any element of the group is a generator, and so a simple hash will suffice.
Otherwise, care must be made to assure that h is orthogonal to g.
Now when we check the transaction balance, we end up with
C
i
1
C
i
2
C
o
1
C
o
2
=
g
s
i
1
h
v
i
1
g
s
i
2
h
v
i
2
g
s
o
1
h
v
o
1
g
s
o
2
h
v
o
2
(41)
= g
s
i
1
+s
i
2
s
o
1
s
o
2
h
v
i
1
+v
i
2
v
o
1
v
o
2
(42)
But if the transaction is balanced, then v
i
1
+ v
i
2
v
o
1
v
o
2
= 0, so
C
i
1
C
i
2
C
o
1
C
o
2
= g
s
i
1
+s
i
2
s
o
1
s
o
2
(43)
We define the sum of the input blinding factors minus the output blinding factors to be
z = s
i
1
+ s
i
2
s
o
1
s
o
2
(44)
Which means that the ratio of the product of the commitments is now just g
z
, and thus we know the private
key z which corresponds to the public key generated from the commitments:
C
i
1
C
i
2
C
o
1
C
o
2
= g
z
(45)
We already know how to sign a public key if we know the private key, which means we can sign this
commitment to zero, and a verifier can check it. This allows a verifier to validate the transaction is balanced.
4.2 Range Proofs
Now that the values can be hidden, we have a new problem. Since we are checking that the sum of the inputs
matches the sum of the outputs, what happens if one of the output values is negative? The transaction will be
balanced, but we will end up minting new coins. How can we prevent this? The answer is via the use of range
proofs [4].
5
First, consider a n-bit binary expansion of v:
v = b
0
2
0
+ b
1
2
1
+ ... + b
n1
2
n1
(46)
If v is in the range [0, 2
64
) then we know that each b
k
0, 1. Remember that we committed to v with
C = g
s
h
v
. Choose a series of s
k
such that
n1
X
0
s
k
= s (47)
Then write commitments for each bit in the binary expansion thus
C
k
= g
s
k
h
b
k
2
k
(48)
As before, the sum of the values in these commitments will be equal to v, but also the sum of the bit blinding
factors s
k
will also equal s. So
C
k
= C (49)
This allows the validator to check that the binary expansion is valid. And if each b
k
0, 1, then one of the
following must be a commitment to zero:
{g
s
k
h
b
k
2
k
, g
s
k
h
b
k
2
k
2
k
} (50)
So either the first or the second terms will reduce to g
s
k
, and since the prover know s
k
he can sign the ring.
We don’t need linkability, so we can use basic ring signatures of size 2. The prover of course knows which term
is actually a commitment to zero, and can sign accordingly.
The range proof thus consists of the n bit commitments C
i
and corresponding ring signatures. The verifier
checks the validity of each bit proof, and then verifies that
C =
Y
C
i
(51)
5 Bulletproofs
Range proofs allow us to verify that output commitments are not negative, but they use a lot of space; each
output range proof consists of 64 separate ring signatures. It would be preferable to somehow consolidate them,
and there are a variety of techniques to do so. Bulletproofs [5] are a compact way to represent aggregated range
proofs, and result in significant space savings.
Bulletproofs are not just useful as aggregated range proofs; more generally, they also have the ability to
represent arbitrary arithmetic circuits. They have similar functionality with zkSNARKs, but require no trusted
setup.
5.1 Notation
The bulletproofs paper uses several notation systems. Some were innovative, like the use of boldfaced group
elements to represent that they were arrays. Some were just obscure, like using the operator to denote pairwise
multiplication of vectors, But other, like using the python[: n] array slicing operator were verbose and annoying.
So pretty much everyone who implented, or tried to explain bulletproofs, emded up replacing something with
their own. Here I will limit myself to replacing the [: n] operator with B for the bottom half and T for the top.
We can do this because we are only ever dealing with powers of two, so it is never ambiguous.
5.2 Improved Inner Product Argument
The heart of a bulletproof is a vector commitment that links a committed value with an inner product. The
prover uses a recursive protocol that at every step cuts the size of the vectors in half and generates a new
commitment, until only a single element remains, then sends the final values with the corresponding generators
and commitment as the proof. The verifier checks that the final commitment is valid, then unwinds the stack.
So for some (g, h) G
n
, (a, b) Z
n
p
, (u, P ) G, c Z
p
, let P = g
a
h
b
and c = ha, bi. The goal is to find
a way to prove knowledge of a and b to someone who knows P and c, without revealing them. To do this, the
prover adds the inner product to the commitment itself:
P = g
a
h
b
· u
ha,bi
(52)
6
Since the goal is to shrink the problem in half, let n
0
= n/2. Since (g, h) are still size n, split each into
bottom (g
B
, h
B
) and top (g
T
, h
T
), with the first n
0
elements in the bottom vector and the second n
0
in the
top. Then for some a
1
, a
0
2
, b
1
, b
0
2
Z
n
p
, define the function H to operate on the split vectors.
H(a
1
, a
0
2
, b
1
, b
0
2
, c) = g
a
1
B
g
a
0
2
T
h
b
1
B
h
b
0
2
T
· u
c
(53)
We can define P in terms of H, splitting the real (a, b) as well into bottom and top:
P = g
a
h
b
· u
ha,bi
(54)
= g
a
B
B
g
a
T
T
h
b
B
B
h
b
T
T
· u
ha,bi
(55)
= H(a
B
, a
T
, b
B
, b
T
, ha, bi) (56)
H is additively homomorphic:
H(a
1
,a
0
1
, b
1
, b
0
1
, c
1
) · H(a
2
, a
0
2
, b
2
, b
0
2
, c
2
) = H(a
1
+ a
2
, a
0
1
+ a
0
2
, b
1
+ b
2
, b
0
1
+ b
0
2
, c
1
+ c
2
) (57)
Now define L, R G:
L = H(0
n
0
, a
B
, b
T
, 0
n
0
, ha
B
, b
T
i) (58)
R = H(a
T
, 0
n
0
, 0
n
0
, b
B
, ha
T
, b
B
i) (59)
Prover sends (L, R) to the verifier, who responds with the challenge x Z
p
. Prover then combines the left
and right parts of (a, b) into single vectors using the challenge:
a
0
= xa
B
+ x
1
a
T
(60)
b
0
= x
1
b
B
+ xb
T
(61)
Prover sends (a
0
, b
0
) to verifier, who first computes P
0
from (P, L, R, x):
P
0
= L
(x
2
)
· P · R
(x
2
)
(62)
Verifier then uses (x, a
0
, b
0
) to calculate Q
0
:
Q
0
= H(x
1
a’, xa’, xb’, x
1
b’, ha’, b’i) (63)
Verifier validates if P
0
= Q
0
. If we expand Q
0
we can see why:
Q
0
= H(x
1
(xa
B
+ x
1
a
T
), x(xa
B
+ x
1
a
T
), x(x
1
b
B
+ xb
T
), x
1
(x
1
b
B
+ xb
T
),
xa
B
+ x
1
a
T
, x
1
b
B
+ xb
T
)
= H(a
B
+ x
2
a
T
, x
2
a
B
+ a
T
, b
B
+ x
2
b
T
, x
2
b
B
+ b
T
, x
2
ha
B
, b
T
i + ha, bi + x
2
ha
T
, b
B
i) (64)
It’s because we get the same thing when we expand P
0
:
P
0
= H(0
n
0
, x
2
a
B
, x
2
b
T
, 0
n
0
, x
2
ha
B
, b
T
i) · H(a
B
, a
T
, b
B
, b
T
, ha, bi)·
H(x
2
a
T
, 0
n
0
, 0
n
0
, x
2
b
B
, x
2
ha
T
, b
B
i)
= H(a
B
+ x
2
a
T
, x
2
a
B
+ a
T
, b
B
+ x
2
b
T
, x
2
b
B
+ b
T
, x
2
ha
B
, b
T
i + ha, bi + x
2
ha
T
, b
B
i) (65)
So if the prover can construct (L, R, a’, b’) such that P
0
= Q
0
, then he must have known (a, b).
5.3 Range Proof Using Inner Product
Let a
L
be a vector with the n bits of v. Then the following must all be true:
ha
L
, 2
n
i = v; a
L
a
R
= 0
n
; a
R
= a
L
1
n
(66)
a
R
is defined to be the negation of a
L
: 0 where 1, and 1 where 0. So any pairwise multiplication between
a
R
and a
L
will be 0.
Given a verifier chosen y G, these relations are equivalent to:
ha
L
, 2
n
i = v; ha
L
, a
R
y
n
i = 0; ha
L
1
n
a
R
, y
n
i = 0 (67)
7
As before, pairwise multiplication between a
R
and a
L
will be 0, regardless of multiplying by y
n
, and summing
the dot product will likewise be 0. And solving the third relation for 0 gives us another dot product of 0 with
our new y
n
.
Using another verifier chosen z G, we can combine these into one relation:
z
2
· ha
L
, 2
n
i + z · ha
L
1
n
a
R
, y
n
i + ha
L
, a
R
y
n
i = z
2
v (68)
Multiplying the first relation by z
2
gives us the z
2
v term, and since the other two relations were 0 we can
add them for free (swapping order and multiplying one by z).
If we expand the inner products, then start isolating prover and verifier terms, we get:
z
2
· ha
L
, 2
n
i + z · ha
L
, y
n
i z · h1
n
, y
n
i z · ha
R
, y
n
i + ha
L
, a
R
y
n
i = z
2
v
z
2
· ha
L
, 2
n
i + z · ha
L
, y
n
i z · ha
R
, y
n
i + ha
L
, a
R
y
n
i = z
2
v + z · h1
n
, y
n
i
Since an inner product ha, bi can be broken into a pairwise/inner product h1
n
, abi:
z
2
· ha
L
, 2
n
i + z · ha
L
, y
n
i z · h1
n
, a
R
y
n
i + ha
L
, a
R
y
n
i = z
2
v + z · h1
n
, y
n
i
a
L
, z
2
· 2
n
+ z · y
n
+ ha
L
z · 1
n
, a
R
y
n
i = z
2
v + z · h1
n
, y
n
i
In order to merge the inner products via the first term, add
z1
n
, z
2
2
n
+ zy
n
:
a
L
z · 1n, z
2
· 2
n
+ z · y
n
+ a
R
y
n
= z
2
v + z · h1
n
, y
n
i + h−z · 1
n
, z2 · 2
n
+ z · y
n
i
a
L
z · 1n, z
2
· 2
n
+ z · y
n
+ a
R
y
n
= z
2
v + z · h1
n
, y
n
i z ·
1
n
, z
2
· 2
n
+ z · y
n
a
L
z · 1
n
, z
2
· 2
n
+ z · y
n
+ a
R
y
n
= z
2
v + z · h1
n
, y
n
i z3 · h1
n
, 2
n
i z
2
· h1
n
, y
n
i
a
L
z · 1
n
, z
2
· 2
n
+ z · y
n
+ a
R
y
n
= z
2
v + (z z
2
) · h1
n
, y
n
i z
3
h1
n
, 2
n
i
Let d(y, z) = (z z
2
) h1
n
, y
n
i z
3
h1
n
, 2
n
i, and we get the final form:
a
L
z · 1
n
, z
2
· 2
n
+ z · y
n
+ a
R
y
n
= z
2
v + d(y, z) (69)
The verifier can calculate the right side (using the commitment V for v), and the problem is now reduced
to an inner product argument.
5.4 Blinding the inner product
We have shown how to make a logarithmically efficient inner product argument, and how to reduce a range
proof to an inner product. But the inner product argument is not zero knowledge, so we can’t use it directly;
we must first blind the parameters.
Let (s
L
, s
R
) be vectors of integers:
(s
L
, s
R
) Z
n
p
(70)
Replace a
L
with (a
L
+ s
L
x) and a
R
with (a
R
+ s
R
x), and the inner product becomes:
(a
L
+ s
L
x) z1
n
, z
2
2
n
+ zy
n
+ (a
R
+ s
R
x) y
n
= z
2
v + d(y, z) (71)
Then construct vector polynomials l(x) and r(x) from the two sides of the inner product:
l(x) = a
L
+ s
L
x z1
n
(72)
r(x) = z
2
2
n
+ zy
n
+ (a
R
+ s
R
x) y
n
(73)
The zeros of these vector polynomials are just the unblinded inner product terms:
l(0) = a
L
z1
n
(74)
r(0) = z
2
2
n
+ zy
n
+ a
R
y
n
(75)
The inner product then becomes
hl(0), r(0)i = z
2
v + d(y, z) (76)
We can express l(x) and r(x) as generic degree one polynomials
l(x) = l
0
+ l
1
x (77)
r(x) = r
0
+ r
1
x (78)
8
Where
l
0
= a
L
z1
n
(79)
l
1
= s
L
(80)
r
0
= z
2
2
n
+ zy
n
+ a
R
y
n
(81)
r
1
= s
R
y
n
(82)
(83)
If we define t(x) as the inner product of the blinded vector polynomials, we get
t(x) = hl(x), r(x)i (84)
We can express this in terms of x:
t(x) = t
0
+ t
1
x + t
2
x
2
(85)
Where
t
0
= hl
0
, r
0
i = z
2
v + d(y, z) (86)
t
2
= hl
1
, r
1
i (87)
t
1
= hl
0
+ l
1
, r
0
+ r
1
i t
0
t
2
(88)
Proving the blinded inner product range proof now depends on simply verifying that both
t
0
= z
2
v + d(y, z) (89)
t(x) = hl(x), r(x)i = t
0
+ t
1
x + t
2
x
2
(90)
6 CryptoNote
CryptoNote [3] is a privacy focused cryptocurrency system which implements many of the techniques explored
above, plus a novel method for tying long term public keys to one time addresses. CryptoNote is defined to use
elliptic curves rather than exponentials, but I will break with that to maintain consistency with the rest of the
document, and use exponentials in this section.
6.1 One time addresses
A CryptoNote key consists of a pair of public keys (A, B) with their associated private keys (a, b). To construct
a one time address, the creator of a transaction starts with a transaction private key r, and an associated
transaction public key R:
R = g
r
(91)
The creator then uses this, with the destination public key (A, B), to construct the one time address y. This
address is a public key, with an associated private key x:
y = g
x
= g
H(rA)
B (92)
The owner of the destination key (A, B) can scan the transaction one time addresses to determine if he is
the owner. He first uses his private key (a, b) to attempt to recover the one time private key x:
x = H(Ra) + b (93)
Then raise g to this power to reconstruct the public key y:
g
x
= g
H(Ra)
g
b
(94)
If y = g
x
, then the destination key was the same one used to construct the one time address, and the key
owner is the owner of the one time address. Since the owner knows the private key x, he is able to sign the key
y in a ring signature, allowing him to spend it.
9
6.2 View keys
One time addresses allow a user to find the transaction outputs which he owns. But this requires the user to
scan the entire blockchain, looking at every output. For users with limited storage and bandwidth, this can be
problematic. It would be preferable to allow a trusted node to do the scanning for the user, while preventing
the node from being able to spend the output.
To do this, the user can pass a tuple of his private key a with his public key B:
V = (a, B) (95)
The node can then look at each transaction, and use the view key with the transaction public key R to
attempt to reconstruct the one time public key y:
Y = g
H(Ra)
B (96)
If Y = y, then the node knows that the one time key belongs to the user, and returns it.
6.3 Ring signatures
CryptoNote uses linkable ring signatures, with external data. It defines a transaction prefix to be all of the
transaction data except for the ring signatures themselves, which includes the input and output public keys,
with the transaction public key and amounts. The transaction prefix is serialized then hashed to create the
signed message m.
7 Monero
Monero is a privacy focused cryptocurrency. In its initial implementation, it used a vanilla implementation of
cryptonote [3]. Later iterations added confidential transactions, with standard range proofs [4]. Recent work
includes upgrading the range proofs with bulletproofs for significant space savings.
7.1 RingCT
The Monero implementation of confidential transactions is called RingCT [4]. It uses MLSAG signatures that
tie a set of Pedersen Commitments to a set of input keys. This is necessary because to verify a confidential
transaction, it is required to have a full set of the commitments used in order to recover g
z
. Without the
MLSAG, any attempt to include the commitments would either be unable to recover g
z
, or would expose the
real input keys.
To accomplish this, the MLSAG signature adds the corresponding commitments to the public key vectors,
then passes them in the signature output:
y
i
= ((y
i,0
, C
i,0
), ..., (y
i,m1
, C
i,m1
)) (97)
When constructing the hashes, the prover signs a final term which is the sum of the input commitments
minus the sum of the output commitments:
g
z
=
C
i
C
o
(98)
L
j,m
= g
v
m
(99)
c
j+1
= H(L
j,0
, R
j,0
, ..., L
j,m1
, R
j,m1
, L
j,m
) (100)
As before, if this sum is a commitment to zero, then it will take the form of a public key g
z
, where the user
knows the private key z. So it can be signed like any other public key in a ring signature. Since the commitment
does not need to be linkable, it is not necessary to include a R
j,m
term, or a key image. It will be necessary to
create a new v
m
and include an additional r
j,m
in the signature:
r
j,m
= v
m
c
j
z (101)
The verifier uses this additional r
j,m
and c
j
to build a standard Schnorr term:
c
j+1
= H(L
j,0
, L
j,0
, ..., L
j,0
, L
j,0
, g
r
j,m
y
c
j
) (102)
As before, if the sum was a commitment to zero, then this term will be the same in the prover and verifier
hashes.
10
8 Zcash
Zcash is one of the more technically advanced cryptosystems available on current exchanges. It uses zero-
knowledge proofs to allow for completely hidden transactions, that can still be validated externally. It divides
its address space into t-addresses, whose details are transparent, and z-addresses, which are hidden from all but
the participants. Money that passes from a t-address to a z-address cannot be tracked, even if it later goes back
to a t-address.
8.1 zkSNARKs
A zkSNARK is a zero-knowledge, short, non-interactive argument of knowledge. It allows the prover to create
a representation of an arbitrary arithmetic or logic circuit, then make proofs about assertions relative to that
circuit. The proofs are computationally difficult to construct, though easier to evaluate, and require a trusted
setup between prover and verifier.
9 Lelantus
There is a new Zerocoin based cryptocurrency system called Lelantus [6], released 2018-12-22. It uses confidential
transactions, and claims to be able to hide the inputs fully while still being auditable.
As per Zerocoin, Lelantus uses the output commitments as the transaction inputs/outputs themselves,
rather than associating the commitments with a one time address as in RingCT. It is thus necessary to reveal
the commitment secret during the spend, similar to the way that CryptoNote reveals the key image. So it is
necessary to make the commitments double blind, or else after secret reveal it would be possible to brute force
the values as per the naive approach to Pedersen commitments. Adapting Lelantus to a more CryptoNote-ish
system could obviate this need, and allow single blinded commitments.
9.1 Σ-protocol for commitment to 0 or 1
Consider a commitment to a message m with random blinding factor r:
c = Com(m, r) (103)
To prove that c opens to 0 or 1, pick random (a, s, t) and use them to construct (c
a
, c
b
):
a, s, t Z
p
(104)
c
a
= Com(a, s) (105)
c
b
= Com(am, t) (106)
In an interactive protocol, the prover would send (c
a
, c
b
) to the verifier, who would respond with the challenge
x. To make it non-interactive, hash (c, c
a
, c
b
):
x = H(c, c
a
, c
b
) (107)
Either way, the prover uses x to construct (f, z
a
, z
b
) and sends it to the verifier:
f = mx + a (108)
z
a
= rx + s (109)
z
b
= r(x f) + t (110)
The verifier now has the full set of (c, c
a
, c
b
, x, f, z
a
, z
b
) and accepts the proof if both of the following are
true:
c
x
c
a
= Com(f, z
a
) (111)
c
xf
c
b
= Com(0, z
b
) (112)
This follows as
c
x
c
a
= Com(xm, xr) · Com(a, s) (113)
= Com(xm + a, xr + s) (114)
= Com(f, za) (115)
c
xf
c
b
= Com((x f)m, (x f)r) · Com(am, t) (116)
= Com(xm fm + am, (x f)r + t) (117)
= Com(xm (mx + a)m + am, z
b
) (118)
= Com(xm m
2
x, z
b
) (119)
11
Since x is not 0, then x(m m
2
) is only 0 when (m m
2
) is 0, or when
m = m
2
(120)
This is only true m 0, 1. So if c
xf
c
b
= Com(0, zb), m 0, 1.
9.2 One out of Many Σ-proofs
Ring signatures allow hiding a signature in a set of mixins. But they grow in size linearly with the mixin set
size. So the mixin set must be limited, and cannot contain every transaction in the ledger. Merkle proofs
offer a logarithmic sized proof for ledger inclusion, but are not zero knowledge. It would be ideal to be able
to demonstrate both ownership and leder inclusion with a single proof. One out of many proofs do this, in
logarithmic size. So every output in the ledger functions as a mixin, and the proof size scales logarithmically
with the ledger size.
Consider a set of N commitments:
c
i
= g
s
i
h
v
i
(121)
If we know that this set contains a commitment to 0, then we know an index l such that
c
l
=
N1
Y
i=0
c
δ
il
i
(122)
is a commitment to zero. This is true because δ
ll
= 1, while all other δ
il
= 0. So this product is simply c
l
as the rest of the c
i
are canceled by raising to 0.
Assuming N = 2
n
, extending as necessary, expand i and l in binary:
i = i
1
...i
n
(123)
l = l
1
...l
n
(124)
We can now express δ
il
in terms of these bits:
δ
il
=
n
Y
j=1
δ
i
j
l
j
(125)
Combining these two terms, our commitment to 0 C becomes
C =
N1
Y
i=0
c
Q
n
j=1
δ
i
j
l
j
i
(126)
Next we iterate over all n bits, committing to the bits of l and proving they are all zero or one using the
previous protocol. After getting the challenge x we will generate an f , but now there is one for each bit of l:
f
j
= l
j
x + a
j
(127)
We can further define f
j,i
j
as a function of f
j
that depends on i
j
:
f
j,1
= f
j
= l
j
x + a
j
(128)
f
j,0
= x f
j
= (1 l
j
)x a
j
(129)
For each i, we can take the product p
i
(x) of the f
j,i
j
terms:
p
i
(x) =
n
Y
j=1
f
j,i
j
(130)
In all cases, f
j,i
j
will be a linear function of x, so p
i
(x) will be a polynomial in x of degree n; but the x term
will cancel j such that l
j
6= i
j
. So i 6= l, at least one of the x terms will cancel; thus
p
i
(x) =
n
Y
j=1
f
j,i
j
=
n
Y
j=1
δ
i
j
l
j
x +
n1
X
k=0
p
i,k
x
k
(131)
12
If we have x, then we can calculate this product directly. But before we have x, we can still evaluate this
polynomial algebraically. If we do so, we can determine the p
i,k
parameters in terms of a
j
. This allows us to
use p
i,k
once we have a
j
:
For all j = (1, ..., n) with k = j 1:
(r
j
, a
j
, s
j
, t
j
, ρ
j
) Z
q
(132)
c
l
j
= Com(l
j
; r
j
) (133)
c
a
j
= Com(a
j
; s
j
) (134)
c
b
j
= Com(l
j
a
j
; t
j
) (135)
c
d
k
=
N1
Y
i=0
c
p
i,k
i
· Com(0; ρ
k
) (136)
The verifier responds with the challenge x, or it is generated via Fiat-Shamir. Prover then uses x as per the
previous protocol to construct, j:
f
j
= l
j
+ a
j
(137)
z
a
j
= r
j
x + s
j
(138)
z
b
j
= r
j
(x f
j
) + t
j
(139)
The prover then constructs the final value:
z
d
= rx
n
n1
X
k=0
ρ
k
x
k
(140)
The verifier must check the individual bit proofs:
c
x
l
j
c
a
j
= Com(f
j
; z
a
j
) (141)
c
xf
j
l
j
c
b
j
= Com(0; z
b
j
) (142)
As before, the first line proves knowledge of l
j
, and the second proves it was binary. Finally, the verifier
checks z
d
against c
d
k
using c
i
and f
j,i
j
:
N1
Y
i=0
c
Q
n
j=1
f
j,i
j
i
n1
Y
k=0
c
x
k
d
k
= Com(0; z
d
) (143)
If we simplify using p
i
(x) and expand we can see why this is true:
N1
Y
i=0
c
Q
n
j=1
f
j,i
j
i
n1
Y
k=0
c
x
k
d
k
=
N1
Y
i=0
c
p
i
(x)
i
n1
Y
k=0
(
N1
Y
i=0
c
p
i,k
i
Com(0; ρ
k
))
x
k
(144)
=
N1
Y
i=0
c
n
Q
j=1
δ
i
j
l
j
x+
n1
P
k=0
p
i,k
x
k
i
n1
Y
k=0
(
N1
Y
i=0
c
p
i,k
i
Com(0; ρ
k
))
x
k
(145)
= c
x
n
l
N1
Y
i=0
c
n1
P
k=0
p
i,k
x
k
i
n1
Y
k=0
Com(0; ρ
k
)
x
k
n1
Y
k=0
(
N1
Y
i=0
c
p
i,k
i
)
x
k
(146)
= Com(0; rx
n
)
n1
Y
k=0
Com(0; ρ
k
)
x
k
n1
Y
k=0
N1
Y
i=0
c
p
i,k
x
k
i
n1
Y
k=0
N1
Y
i=0
c
p
i,k
x
k
i
(147)
= Com(0; rx
n
)
n1
Y
k=0
Com(0; ρ
k
)
x
k
(148)
Com(0; z
d
) = Com(0; rx
n
n1
X
k=0
ρ
k
x
k
) (149)
= Com(0; rx
n
)
n1
Y
k=0
Com(0; ρ
k
)
x
k
(150)
13
9.3 Hiding Transaction Amounts and Origins
Confidential Transactions are good at hiding amounts, but it is necessary to reveal the commitments themselves
in order to prove that a transaction is balanced, i.e. that the sum of the inputs equals the sum of the outputs.
RingCT obfuscates the actual input commitments in a ring of mixins (with both addresses and commitments),
but the data is still present and subject to analysis. It would be better to be able to prove both input ownership
and transaction balance without ever showing the input commitments.
Lelantus accomplishes this via a two step process. It establishes input ownership via a set of one out of
many Σ-proofs, then uses elements of the Σ-proofs to to establish a balance proof. At no time are the input
commitments themselves revealed to the verifier.
To show how the balance proof arises from the elements of the Σ-proofs, consider the following values:
z
i
= v
i
x
n
n1
X
k=0
ρ
i
k
x
k
(151)
Com(0, ρ
i
k
) = g
0
h
ρ
i
k
(152)
The verifier can then compute the following:
A = (
N
new
Y
i=1
C
o
i
)
x
n
= (
N
new
Y
i=1
g
s
o
i
h
v
o
i
)
x
n
= g
s
o
)x
n
h
v
o
)x
n
(153)
B = Com(0,
N
old
X
i=1
z
i
)
N
old
Y
i=1
(
n1
Y
k=0
Com(0, ρ
i
k
)
x
k
) (154)
= g
0
h
(
P
v
i
)x
n
N
old
Y
i=1
h
P
n1
k=0
ρ
i
k
x
k
N
old
Y
i=1
(
n1
Y
k=0
g
0
h
ρ
i
k
x
k
) (155)
= h
(
P
v
i
)x
n
N
old
Y
i=1
h
P
n1
k=0
ρ
i
k
x
k
N
old
Y
i=1
h
P
n1
k=0
ρ
i
k
x
k
= h
(
P
v
i
)x
n
(156)
The ratio of A to B is thus:
A
B
=
g
(
P
s
o
)x
n
g
(
P
v
o
)x
n
g
(
P
v
i
)x
n
(157)
As before, if the transaction is balanced then
X
v
i
=
X
v
o
(158)
And thus
A
B
= g
(
P
s
o
)x
n
(159)
Since the prover knows the output serial numbers, this is a public key to which he knows the private key.
So it suffices to provide a regular Schnorr proof for this ratio to prove that the transaction is balanced, and no
input commitments have been revealed.
10 Mimblewimble
Some of the most recently released cryptocurrencies use a relatively new system called Mimblewimble [8]. The
goals are to implement a system with the benefits of RingCT, but with a pruned blockchain that still verifies
even after removing spent outputs. As a downside, the sender and receiver of a transaction must complete an
interactive protocol.
10.1 One Way Aggregate Signatures
While RingCT uses ring signatures with mixins to obscure the links between inputs and outputs, Mimblewimble
rather aggregates all of the transactions in a block via a technique they call One Way Aggregate Signatures [7].
Thus the individual links between the inputs and outputs of the transactions is lost, and only the block level
linking is still present. This happens naturally as a result of the transaction format.
14
Consider a transaction with input commitments C
i
and output commitments C
o
. As with all implemen-
tations of confidential transactions, the sum of the input commitments minus the outputs will be the ratio of
their products, and this will be a public key to which the owner knows the private key:
Q
C
i
Q
C
o
= g
s
i
s
o
= g
z
= C
T
(160)
The transaction format is thus the set (C
i
1
, ..., C
i
N
, C
o
1
, ..., C
o
M
, C
T
), with a signature on CT to prove the
balance. Given this format, it is trivial to combine transactions; you can simply add the new input, output, and
balance commitments to the existing set, and the balance check should still succeed with the combined sets:
Y
(
Q
C
i
Q
C
o
)
k
=
Y
(C
T
)
k
(161)
A verifier can check the signatures on the individual C
T
and the aggregated balance check; if they all succeed,
the aggregated transaction set is still valid.
Using this technique, miners will aggregate all of the transactions in a block into a single set with a single
aggregated signature. After the new block is formed, nodes can again merge the transactions from the new
block into the set of all transactions. Once this is done, any spent outputs will appear in both the output list
and the input list. Such outputs can be safely pruned from both lists, and a balance check over the entire
ledger will still be valid. This is clear, as any such transactions will appear in both the top and bottom of the
input/output ratio, and will thus cancel each other out.
Thanks to this pruning, Mimblewimble achieves its goal of maintaining a lightweight ledger, with only
unspent outputs and no inputs. This makes the ledger small, only growing with the UTXO set. And for
observers who want to analyze the ledger, there is no way to link transactions.
However, any observer who sees the advertised transactions (either a peer or a miner) has full visibility
into the money flow, and can easily link transactions, since the inputs and outputs are directly listed with
no obfuscation. And all node operators get a list of the inputs and outputs in every block, which gives them
obfuscated access to the same data (though on a per block rather than per transaction level).
Since spent outputs will be removed, it will no longer be possible to validate a block using normal merkle
tree semantics, since this requires having all leaf nodes to construct the root hash. So every output will need
a separate merkle proof, to tie it to the root hash at time of block creation. Validating a block will require
validating each remaining output’s merkle proof.
Finally, while there are indeed space savings from removing inputs and spent outputs, it is necessary to store
all balance commitments C
T
and their associated Schnorr proofs forever. This set grows monotonically with
each added transaction.
11 MobileCoin
MobileCoin is a new cryptocurrency, whose goals are privacy, convenience, and provable correctness. The proof
of concept implementation uses CryptoNote as a transaction format, with the Stellar Consensus Protocol to
achieve blockchain consensus, rather than a wasteful proof of work. All computation on the nodes uses a secure
enclave, to prevent even node operators from having access to view keys or rings.
For maximal convenience, MobileCoin will be introduced directly into secure messaging apps, using mobile
devices’ secure storage for keys. Since there is no mining, transactions will be confirmed quickly. A user will be
able to open a messaging app and quickly send untraceable money, usually within a matter of seconds.
The main weakness of CryptoNote is that the ring signatures contain the actual inputs used in the trans-
action, though these are obscured by a number of mixins. So anyone with access to the ledger can perform a
number of attacks, linking payments to their eventual destinations. This can be used in the common Overseer
scenario, where collusion between two parties can unmask the owners of coins sent by one and cashed out at
the other. So the FBI could send coins to a suspect address, then wait for those coins to make their way to an
exchange, at which point the identity of the owner of the suspect address can be determined.
To address this, MobileCoin currently drops the inputs from transactions before writing them to the ledger,
indeed before the transactions even leave the secure enclave. This guarantees full privacy from ledger analysis,
at the cost of external verifiability. The consensus quorum becomes the arbiter of correctness, and since the
software is open source and anyone can run a node, this functions to attest to the correctness of the ledger.
12 Acknowledgements
The author would like to thank Toby Segaran for initial help on ring signatures, and Isis Lovecruft for the initial
review.
15
References
[1] Schnorr signature. https://en.wikipedia.org/wiki/Schnorr%5Fsignature
[2] Fiat Shamir heuristic. https://en.wikipedia.org/wiki/Fiat%2DShamir%5Fheuristic
[3] Nicolas van Saberhagen. CryptoNote v2.0 October 17, 2013. https://www.bytecoin.org/old/whitepaper.pdf
[4] Shen Noether, Adam Mackenzie, the Monero Research Lab. Ring Confidential Transactions for Monero DOI
10.5195/LEDGER.2016.34. http://eprint.iacr.org/2015/1098
[5] Benedikt Bnz, Jonathan Bootle, Dan Boneh, Andrew Poelstra, and Greg Maxwell. Bulletproofs: Short
proofs for confidential transactions and more Cryptology ePrint Archive, Report 2017/1066, 2017.
https://eprint.iacr.org/2017/1066
[6] Aram Jivanyan. Lelantus: Private transactions with hidden origins and amounts based on DDH 2018.12.22.
https://lelantus.io/lelantus.pdf
[7] Dr. Yuan Horas Mouton. Increasing Anonymity in Bitcoin.
https://download.wpsoftware.net/bitcoin/wizardry/horasyuanmouton-owas.pdf
[8] Tom Elvis Jedusor. MIMBLEWIMBLE 19 July, 2016.
https://download.wpsoftware.net/bitcoin/wizardry/mimblewimble.txt
16