Bank3: enabling temporarily private cryptocurrency transfers

Posted 2024-03-01 by Vincenzo Iovino ‐ 16 min read

Setting and motivation

In this note we put forth a proposal for what we term Bank3. It is essentially an anonymous deposit system (both for Wallets and DAOs).

A Bank3 for Wallets (or just Bank3) is a smart contract $B$ which Ethereum users can deposit coins (ETH) to and withdraw coins from. A sender is a party who wants to deposit coins to a given user Bob via the Bank3. When making a deposit, a sender specifies the amount of coins $n$ to be transferred and a receiver address, that is the address of an Ethereum user who can later claim the coins.

Bank3 can be described by the following example. A sender Alice can deposit anonymously $n$ coins in favour of a receiver Bob by sending the $n$ coins to the Bank3 contract. At any point of time Bob will hold $m\ge n$ coins at the Bank3 contract and can check that, but nobody else will be able to infer how much wealth Bob holds at the Bank3.

Bob can withdraw the $n$ coins deposited by Alice in favour of him using just the ability to use his personal wallet. After withdrawal, the fact that Alice deposited the $n$ coins in favour of Bob is public but it is not possible to leak how many more coins Bob holds at the Bank3.

Security properties

Precisely, the Bank3 protocol preserves privacy in the following sense. After a withdrawal an attacker should not be able to infer the left quantity of coins that the Bank owes to Bob (that is, the amount of coins that Bob can still withdraw from the Bank). This corresponds to the real-world scenario in which Bob withdraws $10k$ euros at the desk of a bank and other customers in the room can see that. So people can infer that Bob owns at least $10k$ euros but they should not be able to know if Bob owns other $300k$ euros or Bob has just $10$ euros left at the bank.

While in the traditional bank scenario the bank's employees can display the Bob's balance, Bank3 is completely decentralized and there is no party at all (except Bob himself) who can infer how much coins Bob holds at the Bank3 at any given point of time. An implication of this property is that each deposit is anonymous until the corresponding coins are withdrawn, that is a deposit does not leak the address of the receiver.

Observe however that it is unavoidable that an adversary can corrupt senders and infer that Bob owns at least the quantity of coins deposited by corrupted senders, that is if Alice and Charlie deposit resp. $2$ and $3$ coins in favour of Bob, an attacker who corrupts Alice and Bob can infer that Bob holds at least $5$ coins at the Bank3.

Another natural requirement of the Bank3 protocol is that only the receiver Bob of a deposit should be able to claim coins from a deposit and nobody else should be able to perform their withdrawal.

We will also consider a light dark variant of Bank3 in which we can have the receiver to be able to withdraw a deposit in favour of any address while hiding the actual receiver of the deposit. That is, Alice can be able to make a deposit in favour of Bob by specifying just some Bob's public information which will be hidden in the deposit even at withdrawal time. Bob can withdraw the deposit from any other pseudonymous Eth address without disclosing that the original deposit was in favour of Bob. The drawback in this case is that Alice can act as receiver as well, that is she can withdraw the coins on behalf of Bob.

Applications

A Bank3 for Wallets would ease the management of wallets. Indeed, in order to preserve privacy, it will not be necessary to create new accounts for each transaction. The latter mechanism is usually adopted by websites who receive donations like Wikileaks.

Unfortunately, this possibility is less user-friendly for shops which might want to display a single QR code encoding their own account in order to not to deal with the creation of multiple accounts. Moreover, regulations might require declaring the amount of coins held in all personal accounts. Using the Bank3 mechanism, the withdrawable coins at the Bank3 might be considered as not part of your yearly revenues. In the dark variant of Bank3 we can have the receiver to be able to withdraw a deposit in favour of any address, and thus a shop could still display a single address to receive payments but with the possibility of withdrawing a given deposit from any other address without leaking that the deposit was in favour of the shop.

Another application is to the management of the treasuries of Decentralized Autonomous Organisations (DAOs) as we will show later. DAOs are not administrated by single users so the creation of multiple accounts to receive payments would be too complex and clashes with the DAO's governance.

Differences with coin mixers

Unlike a coin mixer like Tornado Cash (TC), in a Bank3 system a withdrawal shows where the coins come from (the address of the sender can be deduced).

We can sum up the differences between Bank3 for Wallets and TC as follows.

  • A TC deposit+withdrawal can consume more than 1.3/1.4 milions of GAS whereas in our current Bank3 implementation a deposit (resp. withdrawal) costs about 68k (resp. 35k) and likely we can lower the deposit cost a bit more!
  • TC runs in several seconds on powerful laptops whereas Bank3 can run in fractions of a second even on mobile devices.
  • Bank3 is user-friendly. If Alice fails to save the deposit receipt or Bob loses it, Bob can at any time do an ether scan to find all anonymous deposits in favour of him and be able to make a corresponding withdrawal.
  • Bank3 requires only hashing on-chain and as such is very portable and efficient. A slight variant of Bank3 might be likely implemented also in Bitcoin!
  • Bank3 does not require trusted setup and is based on standard computational assumptions, namely the hardness of breaking discrete logs over elliptic curves whereas it is known that any system based on SNARKs as TC cannot be proven secure from falsifiable assumptions.
  • Bank3 security is weaker than TC: after withdrawal it is visible that Bob made the deposit. This is by design: the purpose here is just to hide the Bob's left wealth at the Bank3 and not to mix the coins. This should not pose legal issues as for coin mixers.

Our Bank3 protocol for Wallets

Suppose a sender Alice wants to send $n$ coins to a receiver Bob identified by the address $addr$ on the Ethereum blockchain. We suppose for now that Alice knows a public key $PK_B$ of Bob, we will later discuss how this can be implemented in a user-friendly way.

In the Bank3 protocol, the sender computes (off-chain) the following values: $A=g^r,C=PK_B^r$, where $PK_B$ is the Bob's public key of the form $g^{sk_B}$ and $r$ is a random value $\in Z_p$, and sets: $CT=(A, B=H(C) \oplus H(addr))$, where $r$ is a random value $\in Z_p$ and $H$ is SHA256 or Keccac.

Then, the sender submits to the Bank3 smart contract the tuple $(n,CT=(A,B))$ along with a deposit of $n$ coins. The Bank3 stores $(n,B)$ in a hash table. Note that it is not necessary to store $A$ in the Bank3 smart contract, we just need this value retrievable via an Ether scan so as to be used for off-chain computations (see later).

Suppose now that the Bob wants to withdraw the $n$ coins corresponding to the deposit for the value $CT=(A,B)$ from the Bank3.

To withdraw the $n$ coins from the Bank DAO, Bob can send to the Bank3's contract $(addr,B, C)$, where $C=A^{SK_B}$. Then, the contract of the Bank3 does the following checks:

    1. $H(C) \oplus H(addr)=B.$
    1. In the hash table corresponding to B, it holds that n>0. If all checks pass, the Bank3 contract updates $(n, B)$ with $(n=0,B)$ to indicate that $n$ coins have been withdrawn, and finally the Bank3 transfers $n$ coins to Bob.

Light dark variant

We can consider the following variant that we term * light dark*. The receiver sets the value $addr$ to a fixed canonical address (e.g., the address of the Bank3 smart contract). In this way, it will not visible at any point which receiver's identity the sender specified at deposit time. The drawback of this variant is that the sender, after having done a payment, can withdraw it at any time acting as receiver. That is, the sender can change his/her mind at any point and take back the coins and the alleged receiver will be always doubtful about being able to claim a deposit.

Usability issues and implementative details

We must specify how Bob generates and distributes his public key $PK_B$. One possibility is to make Bob use his own Ethereum public key (the one corresponding to his Ethereum address). The issue is that Bob would then need to extract his secret key from the wallet and this is not really ideal.

To address these issues we propose to adopt the ZK Registry (ZKReg) proposed by Aragon ZK Research for different but similar purposes. The ZKReg is just a map between Ethereum's addresses and public keys. Alice can associate her own Ethereum address to a public key whose secret key is generated by a password chosen by hers. For instance this password can be deterministically generated as signature of a known message like "Don't sign this message for any application different than the ZKReg"; in this way Alice does not need to know any additional secret beyond her wallet's password.

A research direction is to expoloit Ethereum-ECDSA signatures in a way that would allow anyone to compute a public key of Bob just based on already existing Bob's transactions. In this case the issue is that you would need anyway to retrieve the public key associated to an Ethereum account for example scanning over all Ethereum blockchain seeking for the last transaction signed by Bob's address, and this cannot be even done for addresses who never submitted a transaction.

In the current design we stick to the ZKReg solution adding the following feature: the user can choose to compute the "ZKReg" public key without actually submitting it onchain. In this way, the user can privately communicate such public key to senders in order to receive deposits.

Our Bank3 protocol for DAOs

A Bank DAO (or Bank3 for DAOs) is a smart contract $B$ which other DAOs can deposit coins (ETH) to and withdraw coins from. The word DAO in "Bank DAO" is meant to recall the idea of a bank service for other DAOs but the Bank DAO is just a smart contract without governance functionalities, so a preferable name might be Bank of DAOs.

We assume that each DAO $D$ has a public key $PK_D$ registered in its own contract and there is a public method in each DAO $D$ that wants to make use of the Bank DAO service to enable anyone to retrieve the public key of $D$.

The secret key $sk_D$ corresponding to $PK_D$ has the form $g^{sk_D}$ for some generator $g$ of a cyclic group of prime order $p$, where the secret key $sk_D$ is shared among $D$'s members in a threshold way. The secret sharing is done off-chain, that is there are no traces on-chain of the shares of $sk_D$ or of whoever belongs to the set of participants who share $sk_D$. We can assume the public keys to be Ethereum-like (curve secp256k1) but our approach is generic and we could generalize to different curves or class of public keys. The participants who share $sk_D$ may be even outside the DAO $D$ (e.g., administrators, accountants, etc.), and $PK_D$ can be re-shared periodically so as to guarantee that the public key is the same but the set of participants who share $sk_D$ changes over the time. However, for simplicity we will assume that a withdrawal of coins in favour of a DAO $D$ is done by members of $D$.

In our model we do not deem a security breach the case in which a sender Alice who made a deposit of $n$ coins in favour of a DAO $D$ is later able to withdraw up to $n$ coins in favour of $D$ without permission of $D$ (it would be an attack only if Alice were able to withdraw $\le n$ coins in favour of herself or in favour of any other DAO $D'$ different from $D$).

Suppose a sender wants to send $n$ coins to a DAO $D$ identified by the address $addr$ on the Ethereum blockchain.

In the Bank DAO protocol, the sender computes (off-chain) the following values: $A=g^r,C=PK_D^r$, where $PK_D$ is the $D$'s public key of the form $g^{sk_D}$ and $r$ is a random value $\in Z_p$, and sets: $CT=(A, B=H(C) \oplus H(addr))$, where $r$ is a random value $\in Z_p$ and $H$ is SHA256 or Keccac.

Then, the sender submits to the Bank DAO's smart contract the tuple $(n,CT=(A,B))$ along with a deposit of $n$ coins to the Bank DAO. The Bank DAO stores $(n,B)$ in a hash table. Note that $A$ is not stored by the smart contract of the Bank but it will be visible on the blockchain so as to be used for off-chain computations (see later).

Suppose now that the DAO $D$ wants to withdraw $n$ coins from the Bank DAO. We propose that the DAO $D$ makes a proposal to withdraw $n$ coins from the Bank DAO. The proposal is made in a standardized way so that the Bank DAO can query $D$'s contract to check if a proposal to withdraw such amount of coins was actually submitted and accepted. We skip the details of how this is done but we remark that this can be done in an efficient way.

Suppose that a proposal to withdraw $n$ coins from the Bank DAO has been voted and accepted on the DAO $D$ and suppose Alice is a member of the DAO $D$. Suppose $t$ to be the number of such proposal on the DAO $D$.

To withdraw $m$ coins from the Bank DAO, Alice can send to the Bank DAO's contract $(t,n,addr,B, C)$. We will show later how Alice can compute $C$ in a threshold way. Then, the contract of the Bank DAO gets $PK_D$ by querying the contract $addr$ and does the following checks:

    1. $H(C) \oplus H(addr)=B.$
    1. In the contract with address $addr$ of the DAO $D$ the proposal number $t$ agrees to withdraw $n$ coins from the Bank. This can be done by a simple query to the DAO $D$, that is there should be a public method implemented in all the contracts that want to make use of the Bank DAO protocol that on input an integer $n$ outputs $1$ (resp. $0$) to denote that the last proposal concerned the withdrawal of $n$ coins and it was accepted (resp. rejected).

If all checks pass, the bank contract updates $(n, B)$ with $(0,B)$ to indicate that $n$ coins have been withdrawn, and finally the Bank DAO transfers $n$ coins to $D$. (Additional checks have to be done to guarantee that $D$ cannot withdraw more coins that $D$ holds in the Bank but for simplicity we skipped those tedious details.)

The Bank DAO should also implement a mechanism to keep trace that the proposal number $t$ of the DAO $D$ cannot be longer used to withdraw coins. This can be done by setting a lock flag in the $D$'s contract whenever the Bank DAO queries $D$ to know if the proposal $t$ is in favour of withdrawing $n$ coins so that $D$ will answer negatively to any such future query if the flag is set.

The efficient threshold computation of $C$

Recall that our ciphertext has the form $(A=g^r,B=H(PK_D^r)\oplus H(addr) =H(g^{SK_D\cdot r}) \oplus H(addr))$, where $r\in Z_p$ and $sk_D$ is the secret key corresponding to $PK_D$ and $H$ is SHA256 or Keccac. Let us suppose that the $D$'s members shared $sk_D$ by means of a $t$ out of $N$ secret sharing. Let $S$ be a subset of $[N]$ of cardinality $t$ and for each $i\in S$ let $\lambda_{S,i}$ be the corresponding Lagrange coefficient. For simplicity let us suppose that $S={1,...,t}$, and that $sk_1,\ldots,sk_t$ are the shares of $sk_D$ of the members in the set $S$.

Then, the $t$ members of $S$ can compute (off-chain) the following values: $A_1=A^{\lambda_{S,1}\cdot sk_1}, A_2=A_1\cdot A^{\lambda_{S,2}\cdot sk_2}, ...,A_t= A_{t-1}\cdot A^{\lambda_{S,t}\cdot sk_t}$. This can be done by having each member of the set sending a single value to each other (e.g. via email). In particular, the generic member $i$ needs to broadcast to the other members the value $T_i=A^{sk_i}.$ The values $T_i$'s can be used by each member to compute the value $A_t$ that, by the properties of the Lagrange coefficients, is equal to $PK_D^r=C$, as we had to show. So, we can suppose that the previous threshold protocol ends up with Alice (as any other member of the set) knowing the value $C$ needed to trigger the withdrawal.

Implementation

An implementation of the Bank3 systems can be found here.

Future directions

It would be interesting to investigate whether (a slight variant of) the Bank3 protocol could be ported to Bitcoin.

Also, it would be interesting to investigate whether Bank3 could work as a real bank by staking the coins of the users, making profit from it and distributing the revenues to the users.

Another functionality that can be added in the future is a fallback mechanism in which a deposit that is unclaimed for long time can be claimed by the sender and in the case in which the sender does not claim it for long time the unclaimed coins can be spent by the Bank3's organization.