Giter VIP home page Giter VIP logo

anonymous-zether's Introduction

Anonymous Zether

This is a private payment system, an anonymous extension of Bünz, Agrawal, Zamani and Boneh's Zether protocol.

The authors sketch an anonymous extension in their original manuscript. We develop an explicit proof protocol for this extension, described in the technical paper AnonZether.pdf. We also fully implement this anonymous protocol (including verification contracts and a client / front-end with its own proof generator).

High-level overview

Anonymous Zether is an private value-tracking system, in which an Ethereum smart contract maintains encrypted account balances. Each Zether Smart Contract (ZSC) must, upon deployment, "attach" to some already-deployed ERC-20 contract; once deployed, this contract establishes special "Zether" accounts into / out of which users may deposit or withdraw ERC-20 funds. Having credited funds to a Zether account, its owner may privately send these funds to other Zether accounts, confidentially (transferred amounts are private) and anonymously (identities of transactors are private). Only the owner of each account's secret key may spend its funds, and overdraws are impossible.

To enhance their privacy, users should conduct as much business as possible within the ZSC.

The (anonymous) Zether Smart Contract operates roughly as follows (see the original Zether paper for more details). Each account consists of an ElGamal ciphertext, which encrypts the account's balance under its own public key. To send funds, Alice publishes an ordered list of public keys—which contains herself and the recipient, among other arbitrarily chosen parties—together with a corresponding list of ElGamal ciphertexts, which respectively encrypt (under the appropriate public keys) the amounts by which Alice intends to adjust these various accounts' balances. The ZSC applies these adjustments using the homomomorphic property of ElGamal encryption (with "message in the exponent"). Alice finally publishes a zero-knowledge proof which asserts that she knows her own secret key, that she owns enough to cover her deduction, that she deducted funds only from herself, and credited them only to Bob (and by the same amount she debited, no less); she of course also demonstrates that she did not alter those balances other than her own and Bob's. These adjustment ciphertexts—opaque to any outside observer—conceal who sent funds to whom, and how much was sent.

Users need never interact directly with the ZSC; rather, our front-end client streamlines its use.

Our theoretical contribution is a zero-knowledge proof protocol for the anonymous transfer statement (8) of Bünz, et al., which moreover has appealing asymptotic performance characteristics; details on our techniques can be found in our paper. We also of course provide this implementation.

Prerequisites

Anonymous Zether can be deployed and tested easily using Truffle and Ganache.

Required utilities

  • Yarn, tested with version v1.22.4.
  • Node.js, tested with version v12.18.3. (Unfortunately, currently, Node.js v14 has certain incompatibilities with Truffle; you can use nvm use 12 to temporarily downgrade.)

Run the following commands:

npm install -g truffle
npm install -g ganache-cli

In the main directory, type yarn.

Running Tests

Navigate to the protocol directory. Type yarn.

Now, in one window, type

ganache-cli --gasPrice 0

In a second window, type

truffle test

This command should compile and deploy all necessary contracts, as well as run some example code. You can see this example code in the test file zsc.js.

Detailed usage example

In case you haven't already, navigate to packages/protocol directory and run truffle migrate to compile the contracts.

In a node console, set the variable __dirname so that it points to the packages/protocol directory. Initialize web3 in the following way:

> Web3 = require('web3');
> const web3 = new Web3('http://localhost:8545');
> const provider = new Web3.providers.WebsocketProvider("ws://localhost:8545");

Now, import Client:

> const Client = require(path.join(__dirname, '../anonymous.js/src/client.js'));

The contracts ZSC and CashToken should be imported in node using Truffle's @truffle/contract objects:

> contract = require("@truffle/contract");
> path = require('path');
> const ZSCJSON = require(path.join(__dirname, 'build/contracts/ZSC.json'));
> const ZSC = contract(ZSCJSON);
> ZSC.setProvider(provider);
> ZSC.deployed();
> let zsc;
> ZSC.at(ZSC.address).then((result) => { zsc = result; });

Following the example above, import CashToken:

> CashTokenJSON  = require(path.join(__dirname, 'build/contracts/CashToken.json'));
> const CashToken = contract(CashTokenJSON);
> CashToken.setProvider(provider);
> CashToken.deployed();
> let cash;
> CashToken.at(CashToken.address).then((result) => { cash = result; });

Before proceeding, you should mint yourself some funds. An example is shown below:

> cash.mint(home, 1000, { 'from': home });
> cash.approve(zsc.address, 1000, { 'from': home });

Let's assume now that, in four separate node consoles, you've imported Client and initialized web3 to an appropriate provider in this way. In each window, type:

> let home;
> web3.eth.getAccounts().then((accounts) => { home = accounts[accounts.length - 1]; });

to assign the address of an unlocked account to the variable home.

In the first window, Alice's let's say, execute:

> const alice = new Client(web3, zsc.contract, home);
> alice.register();
Promise { <pending> }
Registration submitted (txHash = "0xe4295b5116eb1fe6c40a40352f4bf609041f93e763b5b27bd28c866f3f4ce2b2").
Registration successful.

and in Bob's,

> const bob = new Client(web3, zsc.contract, home);
> bob.register();

The two functions deposit and withdraw take a single numerical parameter. For example, in Alice's window, type:

> alice.deposit(100);
Initiating deposit.
Promise { <pending> }
Deposit submitted (txHash = "0xa6e4c2d415dda9402c6b20a6b1f374939f847c00d7c0f206200142597ff5be7e").
Deposit of 100 was successful. Balance now 100.

Now, type:

> alice.withdraw(10);
Initiating withdrawal.
Promise { <pending> }
Withdrawal submitted (txHash = "0xd7cd5de1680594da89823a18c0b74716b6953e23fe60056cc074df75e94c92c5").
Withdrawal of 10 was successful. Balance now 90.

In Bob's window, use

> bob.account.public();
[
  '0x17f5f0daab7218a462dea5f04d47c9db95497833381f502560486d4019aec495',
  '0x0957b7a0ec24a779f991ea645366b27fe3e93e996f3e7936bdcfb7b18d41a945'
]

to retrieve his public key and add Bob as a "friend" of Alice, i.e.

> alice.friends.add("Bob", ['0x17f5f0daab7218a462dea5f04d47c9db95497833381f502560486d4019aec495', '0x0957b7a0ec24a779f991ea645366b27fe3e93e996f3e7936bdcfb7b18d41a945']);
'Friend added.'

You can now do:

> alice.transfer("Bob", 20);
Initiating transfer.
Promise { <pending> }
Transfer submitted (txHash = "0x4c0631483e6ea89d2068c90d5a2f9fa42ad12a102650ff80b887542e18e1d988").
Transfer of 20 was successful. Balance now 70.

In Bob's window, you should see:

Transfer of 20 received! Balance now 20.

You can also add Alice, Carol and Dave as friends of Bob. Now, you can try:

> bob.transfer("Alice", 10, ["Carol", "Dave"]);
Initiating transfer.
Promise { <pending> }
Transfer submitted (txHash = "0x9b3f51f3511c6797789862ce745a81d5bdfb00304831a8f25cc8554ea7597860").
Transfer of 10 was successful. Balance now 10.

The meaning of this syntax is that Carol and Dave are being included, along with Bob and Alice, in Bob's transaction's anonymity set. As a consequence, no outside observer will be able to distinguish, among the four participants, who sent funds, who received funds, and how much was transferred. The account balances of all four participants are also private.

In fact, you can see for yourself the perspective of Eve—an eavesdropper, let's say. In a new window (if you want), execute:

> let inputs;
> zsc.contract._jsonInterface.forEach((element) => { if (element['name'] == "transfer") inputs = element['inputs']; });
> let parsed;
> web3.eth.getTransaction('0x9b3f51f3511c6797789862ce745a81d5bdfb00304831a8f25cc8554ea7597860').then((transaction) => { parsed = web3.eth.abi.decodeParameters(inputs, "0x" + transaction.input.slice(10)); });

You will see a bunch of fields; in particular, parsed['y'] will contain the list of public keys, while parsed['C'], parsed['D'] and parsed['proof'] will contain further bytes which reveal nothing about the transaction.

Anonymous Zether also supports native transaction fees. The idea is that you can circumvent the "gas linkability" issue by submitting each new transaction from a fresh, randomly generated Ethereum address, and furthermore specifying a gas price of 0. By routing a "tip" to a miner's Zether account, you may induce the miner to process your transaction anyway (see "Paying gas in ZTH through economic abstraction", Appendix F of the original Zether paper). To do this, change the value at this line before deploying, for example to 1. Finally, include the miner's Zether account as a 4th parameter in your transfer call. For example:

> bob.transfer("Alice", 10, ["Carol", "Dave"], "Miner")

In the miner's console, you should see:

> Fee of 1 received! Balance now 1.

anonymous-zether's People

Contributors

benediamond avatar ibudisteanu avatar johnst99 avatar jpmsam avatar libby avatar stubocka avatar zzy96 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

anonymous-zether's Issues

I have a doubt !!

Hi,
Thanks for the wonderful work you are doing on this protocol.But i seem to have a curiosity as i am going through the code manually with pen/paper.
Below this line, we set up randomness P.randomness = result.tHat;

const P = new PedersenVectorCommitment(bn128.zero); // P._commit(lPoly.evaluate(x), rPoly.evaluate(x), result.tHat);

but the randomness in PedersenVectorCommitment won't be used ( until commitment is done or point in the commitment is read ). https://github.com/benediamond/anonymous-zether/blob/master/packages/anonymous.js/src/prover/innerproduct.js
Is the line redundant ?
I am very sorry, this could be my mistake. however i am going through the code manually understanding/confirming it with the paper. Please pardon me for my mistakes.

Thanks for all the help.

This js realisation only for networks with gasPrice 0?

Hey, in client.js:
const throwaway = web3.eth.accounts.create();
And this new acc sign transfer transaction then (as i understand because "gas linkability"):
web3.eth.accounts.signTransaction(tx, throwaway.privateKey)
But in real network, where gasPrice != 0, how it can be?

TransferOccured is not a function

Issue on windows 10.

How to reproduce:

in node console on the packages/protocol folder run the commands:

__dirname = '[my actual path to]/anonymous-zether/packages/protocol';
const Client = require(path.join(__dirname, '../anonymous.js/src/client.js'));
Web3 = require('web3');
web3 = new Web3('http://localhost:9545');
contract = require("@truffle/contract");
path = require('path');
deployedJSON = require(path.join(__dirname, 'build/contracts/ZSC.json'));
var provider = new Web3.providers.WebsocketProvider("ws://localhost:9545");
var deployed = contract(deployedJSON);
deployed.setProvider(provider);
deployed.deployed();
web3.eth.getAccounts().then(function(result) { accounts = result;});
var home;
web3.eth.getAccounts().then((accounts) => { home = accounts[accounts.length - 1];});
var alice = new Client(web3,deployed,home)

Output error on last command:

Thrown:
TypeError: zsc.events.TransferOccurred is not a function
    at new Client (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\anonymous.js\src\client.js:45:20)

zsc.events contains:

> deployed.events
{
  '0x306c363b04ebfc48d0bc8a89a5fb2e4230c37937d0530d50b8334d50eec63ef0': {
    anonymous: false,
    inputs: [ [Object], [Object] ],
    name: 'TransferOccurred',
    type: 'event',
    constant: undefined,
    payable: undefined,
    signature: '0x306c363b04ebfc48d0bc8a89a5fb2e4230c37937d0530d50b8334d50eec63ef0'
  }
}

Removing the parentheses and brackets from zsc.events.TransferOccurred({}) in packages/anonymous.js/src/client.js the error becomes:

Thrown:
TypeError: Cannot read property 'on' of undefined
    at new Client (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\anonymous.js\src\client.js:47:14)

as expected since there is no attribute TransferOccured in the event

Error: Cannot find module 'fs/promises'

Hello,
When Navigate to the protocol directory,in a second window,type truffle test,meet Error: Cannot find module 'fs/promises'.
Node.js version is v12.18.3.Run in Ubuntu18.Below this line,give the detailed error.
Require stack:

  • /home/konjak/.nvm/versions/node/v12.18.3/lib/node_modules/truffle/build/cli.bundled.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:965:15)
    at Function.Module._load (internal/modules/cjs/loader.js:841:27)
    at Module.require (internal/modules/cjs/loader.js:1025:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.773292 (/home/konjak/.nvm/versions/node/v12.18.3/lib/node_modules/truffle/build/webpack:/external node-commonjs "fs/promises":1:1)

Wish you give me some advise to solve this problem.
Thanks for all the help

Replace Nonce with something better ?

Basically, the functionality required can be summed as tx can be built now, but can be released/mined few blocks later.This would avoid the issue of continuously of recreating transactions and retrying and so on.This may also be necessary considering network propagation of tx/blocks etc. This will also be necessary to bring anonymous-zether to better cope with real life conditions. Right now any tx not mined in the next block has to recreated which will cause major issues in real life conditions.

This functionality is, tx can be mined in later blocks till it can be proven that wallet has not sent any another tx. though it may have received x transfers. in other words, epoch based nonce should be replaced with something better.

The above functionality can be achieved via

  1. open nonce, however it has to provably reveal sender.
  2. open nonce, do not fully reveal sender, but reveal the entire sender ring cryptographically ( ) . we need to increment entire sender ring nonces. but this will fail if someone else chooses same sender ring member as your tx. decrease privacy by a bit, simple to implement but not many benefits. Though collision probability will be less if blockchain has large number of users.
  3. somehow implement it cryptographically. best way possible.
  4. maybe prove cryptographically that this sender ring has not sent any tx between the time it has been made and it has been mined in the blockchain. this can be based on current blockchain state and state when tx was built. this may be possible. may be easy
  5. maybe an encrypted nonce with nizk proof without decreasing privacy ( it needs to be somehow done in a ring, so we do not reveal sender, but it may not be compatible with current design) !!!! still digging.

Thank for help.

Enhancement to protocol to support fees ?

Hi,
I would like to appreciate your hard work for Anonymous Zether Protocol.
I am studying and trying to understand anon zether for a use-case and would like your comments(help). The use-case is a marketplace where items could be traded by sending anon zether from one user to another.
However, the marketplace itself needs a fee (flat per transaction). At this moment, your implementation is ignoring (or has not implemented) the fee structure and as such is unsuitable for marketplace idea and probably main-net block-chain protocols. Please note, fees is also a requirement to enable anon zether on a block-chain (or as a native token). So it is definitely a design requirement.

AFAIK, Fees needs to be open, verifiable, un-cheatable.

I am exploring different ideas but would like your comments on the best method to implement such a functionality without lowering security.
Any idea or points or support code from your side would be very helpful. ( since you are the expert).

Basically, its an enhancement to the protocol to support fees. It can be enabled by default in the protocol with 0 as default fees. unless someone wants to use fees.

Thanks for your help from the bottom of my heart.

deposit error

Following the Readme file, i have deployed the zsc contract and initialised web3
First, in truffle i migrate and then in node i insert the following commands:

__dirname = '[full path to project folder]/anonymous-zether/packages/protocol';
const Client = require(path.join(__dirname, '../anonymous.js/src/client.js'));
Web3 = require('web3');
web3 = new Web3('http://localhost:9545');
contract = require("@truffle/contract");
path = require('path');
deployedJSON  = require(path.join(__dirname, 'build/contracts/ZSC.json'));
var provider = new Web3.providers.WebsocketProvider("ws://localhost:9545");
var deployed = contract(deployedJSON);
deployed.setProvider(provider);
deployed.deployed();
web3.eth.getAccounts().then(function(result) { accounts = result;});
var home;
web3.eth.getAccounts().then((accounts) => { home = accounts[accounts.length - 1];});
deployed.at(deployed.address).then(function(result) {dbg = result});
var alice = new Client(web3,dbg.contract,home)

After these, i follow the command of client.deposit() with the following error:

> alice.deposit(100)
Initiating deposit.
Promise { <pending> }
>
> Deposit failed: Error: Returned error: VM Exception while processing transaction: revert ERC20: transfer amount exceeds balance
(node:19916) UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert ERC20: transfer amount exceeds balance
    at Object.ErrorResponse (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\@truffle\interface-adapter\node_modules\web3-core-helpers\src\errors.js:29:16)
    at Object.callback (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\@truffle\interface-adapter\node_modules\web3-core-requestmanager\src\index.js:170:36)
    at C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\web3-providers-ws\lib\index.js:114:45
    at Array.forEach (<anonymous>)
    at WebsocketProvider._onMessage (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\web3-providers-ws\lib\index.js:102:69)
    at W3CWebSocket._dispatchEvent [as dispatchEvent] (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\yaeti\lib\EventTarget.js:115:12)
    at W3CWebSocket.onMessage (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\websocket\lib\W3CWebSocket.js:234:14)
    at WebSocketConnection.<anonymous> (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\websocket\lib\W3CWebSocket.js:205:19)
    at WebSocketConnection.emit (events.js:210:5)
    at WebSocketConnection.EventEmitter.emit (domain.js:498:23)
    at WebSocketConnection.processFrame (C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\websocket\lib\WebSocketConnection.js:554:26)
    at C:\Users\jsm.DESKTOP-7VJ0LVK\Desktop\anonymous-zether\packages\protocol\node_modules\websocket\lib\WebSocketConnection.js:323:40
    at processTicksAndRejections (internal/process/task_queues.js:75:11)
(node:19916) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 8)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.