Git Product home page Git Product logo

miximus's Introduction

Miximus

Decentralized Ethereum Mixer

Join the chat at https://gitter.im/barrywhitehat/miximus_eth

How it works

When someone sends 1 ether to the deposit function in miximus.sol they append single leaf to the merkle tree.

Afterwards someone who has the secret key (sk) and nullifier of the leaf of the merkle tree is allowed to withdraw 1 ether. But instead of revealing the information to prove that they control it. They (using a zksnark) produce a proof that they know this information without revealing it. They also create a proof that their leaf is in the merkle tree.

When they verify this proof they reveal the nullifier, but not the sk. So no one is able to tell which nullifier maps to which leaf.

To prevent double spends the smart contract tracks the nullifiers and only allows a single withdrawal per nullifiers.

build instructions:

build libsnark gadget and getting the proving key

get dependencies git submodule update --init --recursive mkdir build cd build cmake .. && make

Finally you will need to download the ~400MB proving key from here, unzip it and save it in the ./zksnark_element directory.

Running the tests

Start your prefered ethereum node, cd tests and run python3 test.py This will

  1. Generate verification keys, proving keys, This step takes a lot of ram and its likely your OS will kill it if you have a bunch of windows open.
  2. deploy the contract
  3. Deposit 32 ether in 1 ether chunks.
  4. Withdraw the 32 eth so that an observer cannot tell which deposit it was based upon.

Examples

The examples are interactive and ask you for the addresses you want to send from and to. The contract is deployed on the Rinkeby test net. These scripts deposit and withdraw from that contract. cd examples deposit python3 deposit.py ether this will create a transaction from an account of your chosing to send 1 ether to the smart contract. It will create a files of the forum %d.json where %d is the merkel tree index of your commitment.

python3 withdraw.py will ask you for a file %d.json it will call libsnark and generate a proof with proving key ../zksnark_elements/pk_rinkby.raw python3 withdraw.py takes a long time to run so make sure that your eth.accounts[0] is unlocked by the time the transaction gets broadcast. otherwise it will drop to pdb debugger.

Layer 2 transaction abstraction

A major problem in the current system is who pays for the gas for the withdrawal. While the perfect solution to this is to allow the smart contract to pay for gas. This is not possible at the moment. There for we provide layer two transaction abstraction where a depositor can define a fee that gets paid to whoever pays the gas of a transaction. Future work should formalize a communication channel where people can advertise these transactions so that others can pay the gas for them and recive a reward.

References

This is very similar to babyZoe and its backend Alessandro Chiesa's Zero Cash talk is quite useful to help understand how this works.

miximus's People

Contributors

antiprosynthesis avatar barrywhitehat avatar fulldecent avatar gitter-badger avatar gskapka avatar ldct avatar shogochiai avatar

Stargazers

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

Watchers

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

miximus's Issues

Replace`getSha256` with native javascript hash

When 0x3fdc3192693e28ff6aee95320075e4c26be03309FFFFFFFFFFFFFFFFFFFFFFFF and 0xc9b94d9a757f6a57e38809be7dca7599fb0d1bb5ee6b2e7c685092dd8b5e71db we get leaf 0x06cb95f83223c9c472957b7bb259bc1e2e6f9ddd8abf902e8f03d1a8ebf4c818

Which does not agree with what we get in libsnark.

But lets revisit this after #6 which may solve this.

replace `padZero` by mergeing input[0] and input[1] correctly

libsnarks only allows 253 bit variables. So we end up padding the last two bits of input[2] and input[0]

What we should do is merge input[0] with input[1] and merge input[2] with input[3] which should give us the original merkle tree and nullifier.

padZero is a hack to bypass this for the time being.

Using private keys vs unlocked accounts

Based on readme, I have to run a ethereum node with unlocked account,
I think it would be better if we can specify in .env file public RPC node, Public address, Private key to interact with the blockchain

Implement zksnark prover in javascript

Right now we have to call the cpp code to make a zksnark proof before withdrawing. It would be better if this was done in javascript so that cpp only needs to be called for parameter generation.

Note this will involve loading the verification key which is ~800MB

Ideas to reduce gas costs

Below are some scalability ideas:

  1. 3-pairing SNARKs: The Groth 16 paper reduces the number of pairings from 8 to 3, so that should reduce the gas cost of withdrawals by ~2x.
  2. Offchain roots: A one-liner optimisation is to release the storage of used roots. But there's a better optimisation which is to use some sort of accumulator for the roots so that the full set of roots is not stored onchain. (This is basically the "stateless client" approach.) My suggestion is to use a double-batched Merkle accumulator with a relatively small bottom buffer (e.g. with 1024 entries), or a Merkle Mountain Range. The proof of membership (a Merkle path) could be separate from the SNARK or (even better) part of the SNARK.
  3. Offchain verification: I suggest having two types of withdrawal transactions, "express" and "economy":
    • Express transactions are cleared immediately, as they are now. The downside is that the gas cost to verify the SNARK onchain must be paid.
    • Economy transactions are much cheaper because the SNARK is not verified onchain (in the default case). The downside is that they are slower to clear. They must come with some collateral (say, 1 ETH) and are put in escrow for some challenge period (say, 1 day). During the challenge period anyone can force the verification of the SNARK onchain. If verification of the SNARK fails half the collateral is burnt and the other half goes to the challenger. If verification of the SNARK passes, or the challenge period expires, then the transaction clears and the collateral is returned.
  4. Offchain nullifiers: There may be an opportunity to not store the nullifiers onchain. For economy transactions it suffices to augment the challenge game so that the challenger can submit a proof that a nullifier was previously used. A more general solution that works for express transactions is to put the nullifiers in an accumulator which supports proofs of non-membership. Similar to the proofs of membership for roots, these proofs of non-membership could either be submitted separately from the SNARKs, or merged into the SNARK.

std::bad_alloc on withdraw.py

Hi! I've tried with a couple of different sk/nullifiers but I always get this error while running withdraw.py:

[...]
Output:
93a3ebc1 23e224b8 11893eba df1c49d bb5a1132 88ef57fc a34af2ff d9d97368 
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted

It's not a matter of memory (I've 30GB of free RAM and I've also tried running it as root). Any suggestion?

Thanks!

Internal transfers without revealing the recipient

It would be good to be able to perform an anonymous transfer between two recipients without the ether leaving the contract. As per discussion on AntoineRondelet/snark-mixer#2

This can be achieved by introducing a WithdrawThenDeposit function which does the Withdraw then Deposit logic without the ether leaving the contract. e.g. spend 1 coin, then create another coin with a new owner, with the same value.

However, there are problems: the address that ether is sent to is specified as part of the nullifier, in addition to the salt. If the long-term address of the coin owners is included as part of the nullifier then any coin they own will be revealed, this will link their account to the on-chain actions even if the transactions are submitted by a third party.

One way to get around this is to construct the nullifier using ecrecover, the person submits the (v,r,s) components of the ECDSA signature of all the functions parameters, then the recovered address is combined with the salt to create the nullifier.

Source code refs:

So, the contract functions can be expanded as the recipient no longer needs to be specified in the nullifier - and we can now rely on a signature of the one-time-key for the nullifier to prove ownership of the coin.

  • Deposit
  • WithdrawToSender (sends to msg.sender)
  • WithdrawToAddress (sends to address specified in parameter)
  • Transfer (internal Withdraw then re-Deposit)

However, this raises other questions - how do you find out which coins you have if they haven't been shared with you? One solution to that is to store an encrypted blob along with every Deposit or Transfer which, if you scan all the encrypted blobs using your long-term-key you'll find out which coins you own.

Leading zero added to merkel leaf for some `nullifier`'s

When

nullifier = "0x3fdc3192693e28ff6aee95320075e4c26be03309FFFFFFFFFFFFFFFFFFFFFFF1";
or
nullifier = "0x3fdc3192693e28ff6aee95320075e4c26be03309FFFFFFFFFFFFFFFFFFFFFFFF";
Where
sk = 0xc9b94d9a757f6a57e38809be7dca7599fb0d1bb5ee6b2e7c685092dd8b5e71db
we get

sha256(nullifier, sk) = 0x0a79e59f7bc4a7540bf9c2a96b625c7ea612b734266c89e6f2ec2969babb79cb

The leading zero is not compatible with what we get from libsnark.

Layer 2 transaction abstraction

A major problem in the current system is who pays for the gas for the withdrawal. While the prefect solution to this is to allow the smart contract to pay for gas. This is not possible at the moment. There for we provide layer two transaction abstraction where a depositor can define a fee that gets paid to whoever pays the gas of a transaction. Future work should formalize a communication channel where people can advertise these transactions so that others can pay the gas for them and recive a reward.

We need to find a communication channel to broadcast proofs and some software to monitor this channel and broadcast a proof if it is profitable.

Cmake and Make generate incomplete builds

First, thanks publishing this project! Can't wait to see a product ready trustless Ethereum mixer.

I'm running into some difficulties during the make process.

Because I'm running OSX I'm including additional parameters during the cmake ... && make steps borrowed from the snark-mixer repo. I'm not sure if this is causing issues during the make process, but for whatever reason the /build/src/libmiximus.so file which is required in the test.py/deploy.py files isn't being generated

LD_LIBRARY_PATH=/usr/local/opt/openssl/lib:"${LD_LIBRARY_PATH}"                    
CPATH=/usr/local/opt/openssl/include:"${CPATH}"                                    
PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig:"${PKG_CONFIG_PATH}"          
export LD_LIBRARY_PATH CPATH PKG_CONFIG_PATH       

CPPFLAGS=-I/usr/local/opt/openssl/include LDFLAGS=-L/usr/local/opt/openssl/lib PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig cmake -DWITH_PROCPS=OFF -DWITH_SUPERCOP=OFF ..

The following is the output generated when I attempt to run python3 test.py

Traceback (most recent call last):
  File "test.py", line 24, in <module>
    from deploy import *
  File "../snarkWrapper/deploy.py", line 38, in <module>
    lib = cdll.LoadLibrary('../build/src/libmiximus.so')
  File "/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 434, in LoadLibrary
    return self._dlltype(name)
  File "/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 356, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: dlopen(../build/src/libmiximus.so, 6): image not found

Any thoughts as to why this might be occurring?

Abstract ether to arbiatry erc20 token.

This will allow use with any token. To do this we need to replace

    mapping (bytes32 => bool) roots;
    mapping (bytes32 => bool) nullifiers;

with

    mapping (address => bytes32 => bool) roots;
    mapping (address => bytes32 => bool) nullifiers;

where address is the token address being mixed.

Shielded values, splitting and joining

While a mixer with fixed denominations is a good starting point, without the ability to shield the total value, or splitting and joining coins it has limited use and has side-channel leaks which reveal the total amount of value being transferred (e.g. a 10 ETH transaction requires 10 separate transactions, rather than 1).

Is there a solution that works with the current proving code which would allow for the total value to be shielded, for coins to be split and joined etc. as long as the total value doesn't change (e.g. split a 1 ETH coin into two 0.5 ETH coins).

zero padding issue at MSB in deploy.js

deploy.js exports
tree17 = new BigNumber(tree[17], 16).toString(2).split("").join(" ,");
and several other parmeters needed by ../src/main.cpp for creating a proof. However the current method drops some leading zeros in the output which need to be added by hand inside main.cpp

Add `gasFee` to `nullifier` in javascript and smart contract

We want to be able to pay msg.sender for broadcasting transactions as the recipient may not have any ether. So we need to add to the nullifier a way to express the amout of ether to send to msg.sender.

This does not require a change to the cpp code. Just to javascript and the smart contracts.

in deploy.js the user will set the nullifier to be address + fee + salt currently it is
0x3fdc3192693e28ff6aee95320075e4c26be03309FFFFFFFFFFFFFFFFFFFFFFFA
Where address = 3fdc3192693e28ff6aee95320075e4c26be0330 and salt = FFFFFFFFFFFFFFFFFFFFFFFA

Finaly the smart contract needs to be changed so that nullifierToAddress returns the address and the fee. It then sends fee to msg.sender and 1 ether - fee to recipient

is "cm" bitness ensured?

  1. It's initialized here:
    cm.reset(new digest_variable<FieldT>(pb, 256, "cm"));
  2. Witnessed here:
    cm->generate_r1cs_witness(nullifier);
  3. Thought maybe your unpacker does it, but it's called with false:
    unpacker1->generate_r1cs_constraints(false);

I'd ideally print the constraints related to these variables to see if there are any related to bitness, but didn't have the time.

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.