RingCT vs zk-SNARK: The Ultimate Guide to Monero and Zcash Privacy Mechanisms

It’s tragic that only ten years after the advent of Bitcoin we’re already making a genuine distinction between so-called private and non-private cryptocurrencies. Public-key cryptography is what made cryptocurrency possible and the founders of this revolutionary technology had only one thing in mind when they created it and that is, you guessed it – privacy.

The birth of the cryptocurrency represents a historical moment that cannot be portrayed as just a dot on the graph of technological progress. No. Bitcoin is a political statement. A statement for privacy and financial sovereignty. It didn’t just come out of the clear blue sky, and it wasn’t just Satoshi’s eureka moment; the idea of cryptocurrency has deep philosophical and ideological roots sprawling back to the Cypherpunk movement of the early 90s.

The importance and the entire essence of privacy coins cannot be expressed more suitably in any other way than by simply quoting the first paragraph of the Cypherpunk manifesto: “Privacy is necessary for an open society in the electronic age. Privacy is not secrecy. A private matter is something one doesn’t want the whole world to know, but a secret matter is something one doesn’t want anybody to know. Privacy is the power to selectively reveal oneself to the world.”

This review of the two most prolific privacy mechanism employed by cryptocurrency projects today is a bit more meticulous and technical than you might be used to. It’s a long read and, in all honesty, there’s only so much dumbing down that can be made on a material of this nature. Despite this, if financial privacy is of any concern to you, you’re in the right place.Lets begin.


Monero (XMR) was launched in April 2014. It’s a private, decentralized and fungible cryptocurrency that uses an obfuscated public ledger to obscure the source, destination and amount of all transactions by default. This makes it impossible to link the transaction to any of the participating addresses (i.e. to any person), which is why Monero has been the no. 1 choice of people who seek financial privacy in the cryptocurrency market. This was especially the case in 2016, when Monero’s market cap and transaction volume really picked up the pace due to its adoption in the dark web market, growing at a faster rate than any other cryptocurrency that year. In order to obfuscate information on the blockchain and provide its users with privacy, Monero relies on three major technologies: ring signatures, stealth addresses, and ring CT.

Ring signatures

To protect the sender’s privacy, Monero utilizes so-called ring signatures. Essentially, a ring signature is a type of digital signature which is made up of the merged signatures of multiple signers and, as such, can authorize a certain transaction. The goal of this mechanism is to conceal the actual signer among the rest of the non-signers that compose the signature so that (from the perspective of an outside observer) there’s an equal chance for any of them to have been the actual sender of the transaction.

Here’s how it works behind the curtains:

First off, the ring size is determined. The ring size specifies how many individual signatures it will take to form the ring signature. For example, a ring size of five means that the actual signer’s signature will be combined with four other signatures (also known as decoys), thus forming the ring signature. A larger ring size means lower chances for the transaction to be linked to the actual sender; with a ring size of five (i.e. a mixin count of four), there’s an equal 1-in-5 chance for any of the transaction signers to be the real sender. The decoys are past transaction outputs taken from the Monero blockchain, and the actual signer is a one-time spend key that matches an output being sent from the sender’s wallet. Together, they form the inputs of the new transaction.

Ring signatures allow Monero users to mask the origin of their transactions through the clever use of cryptographic signatures — a characteristic known as Monero untraceability.

Stealth addresses

Monero accounts are associated with a private view key, a private spend key, and a public address made up of a public view key and a public spend key. While there is only one public address per account, all incoming payments are sent to different one-time addresses that appear on the blockchain and cannot be linked to the recipient’s public address. These single-use addresses are called stealth addresses; they are generated by the sender on behalf of the recipient using the recipient’s public address and are unique to the transaction.

In order to help you better understand stealth addresses, we will briefly explore the logic behind them. In the following table we’ve included the characters we will be using in the explanation, as well as the information on whether or not those variables are known to the sender (Alice) and the recipient (Bob):

Known to Alice Known to Bob
(A, B) – The recipient’s public key pair which consists of a public view key (A) and a public spend key (B). The public key pair makes up the recipient’s public address. Yes Yes
(a, b) – The recipient’s private key pair. It consists of a private view key (a) and a private spend key (b). No Yes
r – a random number.

r ∈ [1, l−1];

Yes No
G – a base point.

G = (x, −4/5);

Yes No
R = rG Yes Yes


Here’s how stealth addresses are generated and used on the Monero blockchain:

  1. Alice uses a cryptographic hash function (Hs) to which she feeds the first half of Bob’s public address (A, B) and a random number r. She multiplies the output of the function with the base point G, and thus obtains what is called a shared secret key:


  1. Alice then uses this shared secret key along with the second half of Bob’s address in order to generate P – the one-time public key for the transaction:

P = Hs(rA)G + B

  1. Alongside the destination key, she also packs a value R=rG somewhere in the transaction. She then sends the transaction.
  2. Bob uses his private key (a,b) to search the ledger and check if there’s been any output addressed to him. He does this by calculating the following value for every transaction using his private key a and the value R that is attached to the transaction:

P’ = Hs(aR)G + B

If at any point he comes across a transaction such that aR==rA, then P’==P will be true and he’ll have found Alice’s output that was addressed to him.

  1. Once Bob’s wallet locates and retrieves that output, he is able to calculate a one-time private key:

x = Hs(aR) + b

He can henceforth spend his newly acquired output by signing the transaction with x.

To reiterate, the sender computes the shared secret as rA. When the recipient comes across the transaction, he computes aR. Because of fancy elliptic curve math, the following is true:

A=aG, R=rG => aR==arG==rA

Which means that if the sender computes aR for a given transaction and the result of that operation is the same as rA, then he has successfully found the shared secret and thus recovered the transaction that was meant for him.

Steps 1 through 4 are based on what is known as a Diffie-Hellman exchange – a public key cryptography algorithm that enables two parties to establish a shared secret by utilizing the commutative properties of modulo exponents.

With stealth addresses, only the sender and the recipient of the transaction are able to determine its source and destination; this feature known as Monero unlinkability allows the user to freely display and share his public address, yet the payments he receives cannot be linked to it.

Ring CT

Ring CT is a modification to the Monero protocol which allows for the amounts that are sent in a transaction to be hidden while preserving the network’s ability to verify that the ledger entries still add up. It is based on Gregory Maxwell’s work on Confidential Transactions and, since September 2017, it is mandatory for all transactions on the Monero network.

Prior to Ring CT’s implementation, transaction amounts in Monero needed to be split into specific denominations. This was because a ring signature can only hold together outputs of the same value; for example, an output of 12.5 Monero would be broken up into three outputs (i.e. three separate rings) of 10, 2, and 0.5 XMR in order to process the transaction. Needless to say, outside observers were able to see the transacted amounts, which was unwanted for the privacy-oriented cryptocurrency. With the introduction of RingCT, transactions no longer needed to be broken down into different denominations, and wallets became free to pick ring members from any RingCT outputs regardless of their amount, which brought a significant privacy improvement to Monero.

With RingCT, all outputs on the Monero blockchain have encrypted amounts. The only exception is monero that was created in a coinbase transaction. For those that are a little behind on their crypto vocabulary, a coinbase transaction is a transaction that creates XMR according to Monero’s emission schedule (out of thin air, so to say). Newly created monero firstly resides in outputs that have visible amounts and, when they are transferred for the first time, RingCT outputs with masked amounts are generated. These encrypted amounts can only be decrypted by the transaction recipient.

So, how was this made possible?

In order to understand all of this encrypting and decrypting, masking and unmasking, we first need to do a quick overview of the basic tools that confidential transactions are based on — Pedersen commitments and range proofs.

Pedersen commitments

Image credits:

A commitment scheme lets you keep a piece of data secret, but commit to it so that it cannot be changed at a later time. Think of commitments as boxes; the sender puts something in the box, locks it and sends it to the receiver. Neither he can change the contents of the box (because he already sent it), nor can the recipient (because he doesn’t have the key). The contents of the box can only be revealed when the sender shares the key with the recipient. Commitments are binding; that is, once you’ve generated the commitment (i.e. committed to the data), you cannot change its value.

To form a commitment, you need two things: the data and a binding factor. Here’s a simple commitment scheme constructed using the SHA256 hash function:

Commitment = SHA256(binding_factor || data)

The binding factor is a random number; it is necessary because, without it, it might be easy to brute-force guesses for the data and compare them to the commitment until you find the true value. If you share the commitment with another person, they cannot determine the data that you’ve committed to. However, you can later reveal the data and the binding factor to that person and they can run the hash for themselves to verify that you indeed committed to the same data you revealed.

Let’s move on to the fun part.

A Pedersen commitment is much like the above example, except that it also has one additional property: Pedersen commitments can be added, and the sum of a set of Pedersen commitments equals a commitment of the sum of the data and a sum of the binding keys;

C(BF1, data1) – C(BF1, data1) == 0

C(BF1, data1) + C(BF2, data2) == C(BF1 + BF2, data1 + data2)

This latter is known as the homomorphic addition property. This useful relation can be used to prove that the sum of the transaction inputs equals the sum of the transaction outputs without having to reveal the exact amounts, which is the whole idea behind the Ring CT protocol. In other words, Monero uses Pedersen commitment schemes (and their homomorphic addition properties) to encode the value of all transactions that participate in the ring signature.

The encoding (or masking) of the transaction amount is done using the ecdhEncode method. Without getting too technical, the method takes the transaction amount, a binding factor and the shared secret (remember the aR==rA relation that we discussed above?), and uses the shared secret to encode the binding factor and the amount so that only the recipient can decode it.

The ring signature lists both the real input and the decoy inputs as being spent in the transaction, therefore the homomorphic addition property is rendered useless to the outside observer as he doesn’t know which inputs are really being spent and, consequently, which Pedersen commitments need to be summed. This isn’t a problem for the RingCT mechanism though, because the ring signature only has to prove that there’s one combination of inputs for which the sum of the outputs is equal to the sum of the inputs. Due to mathematical reasons, this proof is impossible to forge.

Proving that the transaction amounts sum to zero is the same as proving that you know the private key for at least one of the Pedersen commitments of the ring signature (N signatures in the ring signature = N Pedersen commitments). In other words, in order to prove that at least one of the combinations of possible inputs and outputs in the transaction sums to zero, you will have to provide the private key needed to decode the Pedersen commitment of that combination. Clever, right?

Range proof

Consider the following example:

The sender owns 1 XMR. He creates a transaction that has two outputs: one with a value of 100 XMR (that he addresses to himself), and another with a value of -99 XMR.

Seeing as 100 + (-99) = 1, this transaction is arithmetically correct and the sum of the outputs does, in fact, equal the sum of the inputs. In other words, this transaction is in accordance with the Pedersen commitment scheme. The transaction amounts are being taken from a finite range that uses modular arithmetic, which means that the sender can use negative numbers to produce large output amounts. So, what’s stopping him?

To prevent this from happening and prove that the transaction outputs aren’t negative, Monero utilizes range proofs. Put simply, a range proof proves that the encrypted transaction amount must have been created by the addition of a series of positive powers of 2, without actually disclosing what those powers of 2 are. It prevents senders from using negative binding factors (and, thus, cheating the system) by proving that the factors lie within a certain permitted range.

When a user sends a Monero transaction, he needs to spend his entire output and return the change to himself (since outputs can’t be spent twice). For example, if the sender owns an output of 12.34 XMR and wants to send the recipient 2.1 XMR, the transaction would have one input (12.34 XMR) and two outputs (2.1 XMR for the recipient, and a 10.24 XMR change for the sender which is sent back to his wallet).

In order to enable the network to verify that the Monero used in the transaction hasn’t been fabricated, and confirm that the input amounts of the transaction are equal to the outputs, Monero utilizes Pedersen commitments and range proofs.

Although they may look like random numbers, Pedersen commitments allow the sender to reveal just enough information about the transaction output for the network to confirm the transaction by confirming that the sum of the transaction inputs is equal to the sum of the transaction outputs, without the need for them to publicly disclose the exact amount that they’re spending.

Range proofs are used to secure the supply of Monero by preventing senders from committing to negative values. They do this by cryptographically proving that the transaction amounts are greater than zero and less than some arbitrary number.

Thanks to Monero’s RingCT, an outside observer cannot deduct the actual amounts involved in a transaction nor the ratio of one input or output to another, but the miners are still able to verify that the transaction is legitimate and should be accepted by the network.


Zcash (ZEC) was released in October 2016. It is a privacy-oriented cryptocurrency that uses a public blockchain but keeps the source, destination and amount of all transactions private. One major difference between Monero and Zcash is that Zcash’s privacy feature is optional and does not come as a default. To guarantee transaction validity without revealing the actual data, Zcash uses a different kind of privacy mechanism called zk-SNARKs or – zero-knowledge proof constructions. Let’s see how it operates:


The acronym zk-SNARK stands for “zero-knowledge succinct non-interactive argument of knowledge”. Let’s break it apart and understand what all these words really mean in the context of Zcash’s privacy mechanism.

  • Zero-knowledge proofs allow one party (the prover) to prove to another party (the verifier) that they know a certain piece of information without actually disclosing the piece of information to the other party as evidence. Essentially, an argument is zero-knowledge if it doesn’t leak any information other than the truthfulness of the statement at hand.

To best understand this concept, let’s look at an example. Let’s say that the prover has two differently-colored (but otherwise indistinguishable) balls: one is red and one is green. He wants to prove to the verifier, who is colorblind, that the balls are indeed colored differently. Obviously, the verifier cannot visually confirm the prover’s statement, so he will have to rely on some kind of proof system that will simultaneously prove to him that the balls are differently-colored whilst not revealing which one is red and which one is green.

A zero-knowledge proof in this scenario would look as follows:

The verifier takes the balls and puts them behind his back, holding one ball in each hand. He takes one of the balls from behind his back, shows it to the prover, and hides it again. He can then switch the balls behind his back or not, after which he once again takes a ball out from behind his back. He shows it to the prover and asks him if the ball was switched.  If the balls were indeed a different color, the prover could answer with certainty by simply looking at the balls whether or not the verifier switched them behind his back. On the other hand, if they were the same color and, hence, identical, the probability of the prover guessing correctly is 50%. The experiment can be repeated as many times as necessary to prove that the subsequent correct guesses of the prover aren’t random.

In order for a proof system to be considered zero-knowledge, it must satisfy three properties:

  1. Completeness – If the statement is true, an honest prover can convince an honest verifier of this fact by properly following the protocol.
  2. Soundness – If the statement is false, a dishonest prover cannot convince an honest verifier that it is true, except with some small probability (known as a soundness error).
  3. Zero-knowledge – If the statement is true, the verifier doesn’t need to learn anything else other than the fact that the statement is true in order to verify it.

Ring signatures are zero-knowledge systems as well – an outside observer has no idea which key was used to sign the transaction but can verify that it was legitimate.

  • Succinct zero-knowledge proofs can be verified in as little as a few milliseconds. This is due to the fact that the length of the proof is not affected by the size of the statement that it’s proving; even for very large pieces of data, the zero-knowledge proof can be packed in a few hundred bytes.
  • Non-interactive zero-knowledge proofs don’t require a back-and-forth communication between the prover and verifier. Instead, the proof consists of a single message that the prover sends to the verifier. The way this is achieved is by generating a common reference string that the prover and verifier share (a public parameter of the system)

Much like it is with Monero, the sender of a Zcash transaction needs to construct a proof to show that (a) the sum of the input amounts is equal to that of the output amounts, (b) the sender owns the private spending keys necessary to spend the input amounts (i.e. input notes) and (c) the private spending keys are linked to the transaction in such a way that the transaction cannot be modified without them.

The shielded equivalent of a Bitcoin UTXO (unspent transaction output i.e. the input for the new transaction) in Zcash is called a commitment (not to be confused with a Pedersen commitment). Spending that commitment involves revealing a matching nullifier. Nullifiers serve to allow the network to distinguish between spent and unspent notes. All created commitments and revealed nullifiers are kept in lists by the Zcash nodes. In order to avoid disclosing any information about the commitments, or the relationship between a certain commitment and a nullifier, both commitments and nullifiers are stored in their respective lists as hashes.

A commitment is published every time a shielded payment is used to create a new note. It consists of the recipient’s address, the amount being sent, a unique identifier rho (ρ), and a random nonce (number used only once):

Commitment = SHA256 (recipient address, amount, rho, r)

In order to spend a shielded transaction, the sender uses his public key to publish the commitment’s nullifier and provides the network with a zero-knowledge proof that he is authorized to spend the inputs. By publishing the nullifier, the sender invalidates their note and at the same time generate a new note that can be controlled by the recipient. The nullifier is generated by hashing the secret unique number rho that we mentioned above.

Nullifier = SHA256 (Spending key, rho)

This nullifier must not already be in the list of nullifiers that the nodes use to keep track of spent transactions.

By checking the nullifier list we made sure that the notes haven’t already been spent. However, we didn’t check if they belonged to the sender, nor if they are ‘real’ in the sense that their hashes exist in the node’s table of hashed notes. This could be fixed really easily if the sender would simply publish the note itself rather than its hash, but that would get rid of the privacy that we’re trying to achieve.

Enter zero-knowledge proofs.

In addition to the steps above, the sender will publish a proof-string π for the shielded transaction which verifies that (a) a revealed commitment exists for each input note, (b) both the note commitments and the nullifiers were computed correctly, and (c) it is computationally and financially infeasible for the nullifier of an output note to collide with another nullifier of a different note, thus completing the set of information that the network needs to verify the legitimacy of the transaction without actually revealing any sensitive information about it.

In order to create and check proofs, Zcash makes use of an additional set of keys. These special proving and verifying keys were generated in what is known as the public parameter ceremony and are shared among all the participants in the Zcash network. For each shielded transaction, the sender uses their proving key to generate a proof that their inputs are valid. Zcash miners then check that the transaction follows consensus rules by checking the prover’s computation using the verifying key. Zcash’s proof generation process offloads the major part of the computational work to the transaction sender (which can take up to 40 seconds), and leaves the prover with a short verification process (usually takes milliseconds.)

Although this guide touches on technical aspects of our cryptocurrencies of choice, there’s only so much simplifying we can do and at the same time remain true to the original content. Because of this we suggest that, if you’re curious to find out more about Zcash’s privacy mechanism, you refer to Vitalik Buterin’s three-part series on zk-SNARKs and Zcash’s protocol specification.


Image credits:

Both zk-SNARKS and RingCT have their own unique advantages and disadvantages. The main objections directed towards Monero’s privacy mechanism spawn from a paper titled “An Empirical Analysis of Linkability in the Monero Blockchain” that was originally published in April 2017. This monumental critique of Monero’s privacy mechanism was overhauled, and a completely new paper titled “An Empirical Analysis of Traceability in the Monero Blockchain” was published a year later in April 2018. The second version of the paper (written by the same authors) improved upon the original in many ways, and this scientific contribution to Monero’s development was recognized and promptly addressed by the team behind the Monero project. In the response to 2nd version of the paper, Monero developers summarize the following:

“The paper ends with three recommendations: 1) updating the decoy sampling distribution, 2) avoiding publicly deanonymized outputs as decoys (eg: public pool payouts), and 3) warning users their transactions before RingCT are vulnerable to tracing analysis.”

The developers agree with the first two points and stand by their statement that they’ve always been transparent about Monero’s limitations. Additionally, the Monero team emphasizes that the largest vulnerability outlined in the original paper – over two years ago – was mitigated over a year before, and was nearly completely resolved before the first version of the paper was published. Furthermore, it must be noted here that RingCT is a much older privacy mechanism than zk-SNARKs and it has been a subject of many years of extensive peer review.

Zk-SNARKs’ main criticisms can be boiled down to three points: 1) it’s creation required a trusted setup – which is a security concern on its own, 2) it’s very resource heavy – which hinders adoption and makes it slow, and 3) it’s not private by default – which makes it less private overall.

The first point is acknowledged by Zcash’s team and (arguably) sufficient measures have been taken to mitigate the security risks posed by the trusted setup. However, regardless of these measures, if all parties involved in the trusted setup collude they’ll have the possibility to create an unlimited number of coins without detection — and this is a security problem that still persists today.

— On a side note, Radiolab aired an incredibly intriguing podcast which gives the listeners a first-row seat in The Ceremony (of Zcash’s creation.) It’s a real thriller and I highly recommend that everyone listens to it.

The objections raised in the second and third point are the “real” problem here; because the private transactions are slow and resource-heavy, they’re not practical for old and/or mobile hardware. This hinders adoption and consequently limits the already limited privacy. The reason for this is encaptured in the following explanation made by Vitalik Buterin:

”The basic reason why creating a proof is so hard is the fact that what was a single binary logic gate in the original computation turns into an operation that must be cryptographically processed through elliptic curve operations if we are making a zero-knowledge proof out of it. This fact, together with the superlinearity of fast Fourier transforms, means that proof creation takes ~20–40 seconds for a Zcash transaction.”

Unfortunately for Zcash, in the world of privacy coins – it’s either default privacy or no privacy. Just to prove this point, when the FBI brought down the founder of the Alphabay darknet market, they were able to identify that he had 8,309 Ethereum, 3,691 Zcash and “an unknown amount of Monero.” And this pretty much says everything.

This guide focuses on privacy, make sure to read our guides on Monero and Zcash and our Monero vs Zcash Comparison to better inform yourself on each coin.

Featured image