To support the user privacy, is it possible to hide the sender address or receiver address of transactions by "zk-SNARK" or "Bulletproofs" ? Or we’ll be able only to hide the value that is mapped to an address ?

Assume the following mapping:

mapping (address => bytes32) userData;

Normally, using non-interactive zero-knowledge proofs (like "zk-SNARK" or "Bulletproofs"), we are able to hide the value that is mapped to an address (i.e. userData) as follows:

mapping (address => bytes32) userDataHash;

And then by zero-knowledge proofs, we can prove that if userDataHash meets a condition? For example, prove that an encrypted number is in a given range, without revealing anything else about the number.

However, assume that instead of Data, we want to hide sender of transaction (i.e. address). We want to keep confidentiality of the user/sender himself, instead of their data.

Is it possible ? And if yes, How ?

Is it possible to use Confidential Addresses for this purpose?

2 Answers 2


Roughly, there are three aspects relative to privacy of transactions.

  1. Hiding the sender of the transaction -> Ring Signatures. See Will be a ring signature scheme possible to implement at Ethereum? for a PoC in Ethereum.
  2. Hiding the receiver of the transaction -> Stealth Addresses (like used in Monero). See https://monero.stackexchange.com/questions/1500/what-is-a-stealth-address. I am not aware of a PoC in Ethereum.
  3. Hiding the content of the transaction -> Zero-Knowledge-Proofs. See What are zkSNARKs? How do they work?, zk-SNARKs vs. Zk-STARKs vs. BulletProofs? (Updated), and Is there a decentralized zk-SNARK (zero-knowledge Succinct Non-Interactive ARgument of Knowledge)?

Now, there is a point where I am not 100% sure. zcash has the concept of shielded addresses which is similar to ring signatures / stealth addresses from monero. From this blog post https://medium.com/coinmonks/monero-vs-zcash-and-the-race-to-anonymity-4322b0a9bd90 it reads like it is possible to implement shielded address with ZK-SNARKs (?):

Zcash enables optional features to enable privacy for transactions including the sender, receiver, and amount. Zcash addresses beginning with a “t” (t-addrs) are considered transparent, and are similar to bitcoin transactions. “Shielded” transactions are used with addresses beginning with a “z” (z-addrs), and these are considered to be fully anonymous. It’s important to note that as of December 2017 only 4% of Zcash transactions were being shielded.

With a z-addr, zk-SNARKs are used to hide the outputs to and from the z-addr. Therefore a transaction from a t-addr to a z-addr would show the ZEC leaving the t-addr but the output would be hidden to the z-addr.

UPDATE: I just stumbled upon this one. It is possible to achieve privacy in all three aspects (sender, receiver, value) with ZK-SNARKS only. See https://medium.com/@atvanguard/zkdai-private-dai-transactions-on-ethereum-using-zk-snarks-9e3ef4676e22 for an example using the ZoKrates library.

  • 1
    Tested myself, sending from t to z requires the generation of a zkSNARK, sending from z to t also requires a zkSNARK. Only t to t doesn't require a zkSNARK, hence why no light client allows sending or receiving using z addresses (SNARK generation requires upwards of 4 GB of memory concurrently)
    – Expectator
    Commented Jan 8, 2019 at 23:22

Strictly speaking, it is not possible to hide the sender of an Ethereum transaction. This is due to the fact that it is possible to extract the public key of the sender, and thereby the address, directly. A valid Ethereum transaction contains v, r, s (among other fields) which makes up the ECDSA signature.

Here is an example of public key extraction from ethereumjs-utils:

 * ECDSA public key recovery from signature
 * @param {Buffer} msgHash
 * @param {Number} v
 * @param {Buffer} r
 * @param {Buffer} s
 * @return {Buffer} publicKey
exports.ecrecover = function (msgHash, v, r, s) {
  const signature = Buffer.concat([exports.setLength(r, 32), exports.setLength(s, 32)], 64)
  const recovery = v - 27
  if (recovery !== 0 && recovery !== 1) {
    throw new Error('Invalid signature v value')
  const senderPubKey = secp256k1.recover(msgHash, signature, recovery)
  return secp256k1.publicKeyConvert(senderPubKey, false).slice(1)

A valid transaction also contains a to field which can be receiver address (when sending ethers) or the address of a smart contract. It is null when deploying a new contract (from Solidity docs):

If the target account is not set (the transaction does not have a recipient or the recipient is set to null), the transaction creates a new contract.

That means that you can theoretically hide the address of the receiver if you create your own token contract using zero-knowledge proofs. You could probably implement a protocol similar to Zcash, but people will be able to retrieve the address of the sender. This might or might not be a problem according to your requirements. As a side node, there is a nice proof-of-concept ethereum mixer that uses zk-SNARKs.

I am not familiar with Elements Confidential Addresses, but according to Elements website they use their own blockchain that can optionally be pegged to another blockchain (it is deployed as a side-chain; a blockchain like Ethereum is used as a trust anchor). It is therefore not directly related to Ethereum.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.