ethereum934
eth-mimblewimble
Python

Ethereum 9 3/4's zk-SNARKs circuits and the python library for Mimblewimble on Ethereum

Last updated Dec 1, 2025
80
Stars
10
Forks
10
Issues
0
Stars/day
Attention Score
36
Language breakdown
No language data available.
โ–ธ Files click to expand
README

Ethereum 9ยพ

Send ERC20s privately using Mimblewimble and zk-SNARKs!

Summary

Please check out technical details here.

  • Ethereum 9ยพ uses Mimblewimble transaction and it prevents printing money out of thin air.
  • With spent tags(nullifier), Ethereum 9ยพ completely hides where the inputs come from.
  • Ethereum 9ยพ manages TXOs using zk RollUp. Thus it stores only the root value of the tree on Ethereum.
  • It uses Pedersen Merkle Mountain Range for its data structure and it allows an efficient zk-RollUp.
  • It also supports optimistic roll up to reduce the gas costs per transactions.
  • Using optimistic roll up, relayers can aggregate transactions up to 32 txs at once and collect transaction fees.

Pre-requisite

Install docker and configure to allow at least 13GB memory. Install GNU Make & Python3 & Python virtualenv

You can run some of the tests below without docker using test-host... instead of test... command below. In this case you will have to install ZoKrates

Make commands

  • make test: Test circuits, python library, and contracts
  • make test-circuits: Test zk-SNARKs circuits
  • make test-py934: Test python library for Mimblewimble & Pedersen MMR tree
  • make test-conctracts: Test Ethereum934.sol contracts & zk-SNARKs verifier contracts

What does this project include

  • zk-SNARKs Circuits
โ”œโ”€โ”€ circuits
    โ”‚ย ย  โ”œโ”€โ”€ mmr
    โ”‚   โ”‚ย ย  โ”œโ”€โ”€ ...
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkMMRInclusion.zok # Verfies inclusion of an item in the given MMR root.
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkRollUp1.zok # Updates MMR root appending 1 item.
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkRollUp2.zok # Updates MMR root appending 2 items.
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkRollUp4.zok # Updates MMR root appending 4 items.
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkRollUp8.zok # Updates MMR root appending 8 items.
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkRollUp16.zok # Updates MMR root appending 16 items.
    โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ zkRollUp32.zok # Updates MMR root appending 32 items.
    โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ zkRollUp64.zok # Updates MMR root appending 64 items.
    โ”‚   โ”œโ”€โ”€ ...
    โ”‚ย ย  โ”œโ”€โ”€ zkDeposit.zok # Verifies depositing spent tag(nullifier) satisfies the given condition.
    โ”‚ย ย  โ”œโ”€โ”€ zkMimblewimble.zok # Verifies the transaction satisfies the Mimblewimble protocol.
    โ”‚ย ย  โ”œโ”€โ”€ zkRangeProof.zok # Verifies the given TXO's value is between the given range.
    โ”‚ย ย  โ””โ”€โ”€ zkWithdraw.zok # Verifies the withdrawing TXO exists in the given root.
    โ”œโ”€โ”€ containers: Dockerfiles to make proof generator containers using the above circuits.
    โ”œโ”€โ”€ tests
    โ”‚ย ย  โ”œโ”€โ”€ circuits
    โ”‚   โ”‚ย ย  โ”œโ”€โ”€ ...
    โ”‚   โ”‚ย ย  โ””โ”€โ”€ unitTest.zok # Tests Mimblewimble circuits and MMR circuits
    โ”œโ”€โ”€ utils
    โ”‚   โ””โ”€โ”€ createchallengecircuit.py # Forked from Zokrates utils. It generates a circuit to calculate tx challenge.
  • Py934: Python library for Mimblewimble transaction and Pedersen MMR tree.
โ”œโ”€โ”€ py934
    โ”‚ย ย  โ”œโ”€โ”€ ...
    โ”‚ย ย  โ”œโ”€โ”€ jubjub.py # Implements field on the BabyJubjub curve
    โ”‚ย ย  โ”œโ”€โ”€ mimblewimble.py # Implements Mimblewimble transaction builder for Ethereum 9 3/4
    โ”‚ย ย  โ””โ”€โ”€ mmr.py # Pedersen MMR implementation
    โ”œโ”€โ”€ tests
    โ”‚ย ย  โ”œโ”€โ”€ test_field.py # Test BabyJubjub curve arithmetics.
    โ”‚ย ย  โ”œโ”€โ”€ test_mimblewimble.py # Test Mimblewimble transaction building library
    โ”‚ย ย  โ””โ”€โ”€ test_mmr.py # Test python implementation of Pedersen MMR
    โ”œโ”€โ”€ sample.py # Script to generate test dataset. They will be used for solidity testing.
    โ”œโ”€โ”€ setup.py # Py934 PyPI configuration
    โ”œโ”€โ”€ requirements.txt # Python package dependency
    โ”œโ”€โ”€ requirements-dev.txt # Python packages for development environment
  • Smart contracts: Solidity smart contracts to verify ZKPs
โ”œโ”€โ”€ contracts
    โ”‚ย ย  โ”œโ”€โ”€ generated # Automatically generated Verifiers using Zokrates
    โ”‚ย ย  โ”œโ”€โ”€ ...
    โ”‚ย ย  โ”œโ”€โ”€ Ethereum934.sol # Main application
    โ”‚ย ย  โ”œโ”€โ”€ ZkInterfaces.sol # Interface to call zkp verification functions
    โ”‚ย ย  โ””โ”€โ”€ ZkSANRKs.py # Solidity to get artifacts of automatically generated contracts
    โ”œโ”€โ”€ tests
    โ”‚ย ย  โ”œโ”€โ”€ dataset # json files generated by sample.py
    โ”‚ย ย  โ”œโ”€โ”€ Ethereum934.test.js # Test depositing, rollin up, withdrawing. Using scenarios are here.
    โ”‚ย ย  โ””โ”€โ”€ ZkSANRKs.test.js # Test and benchmark how much each ZK verification function costs
    โ”œโ”€โ”€ package.json # Makes Ethereum934 contract as a node module
    โ”œโ”€โ”€ truffle-config.json # Truffle framework configuration
    โ”œโ”€โ”€ scripts # Testing scripts for solidity

How to build transaction and submit to Ethereum?

  • Deposit and create a coinbase
txo = Output.new(132)
   depositproof = txo.depositproof
Make a txo to deposit 132 amount of ERC20 tokens. You need to submit the deposit proof to use that txo. The deposit proof guarantees that you know the secret keys and the value will not occur overflow during zk-SNARKs computation.
  • Inclusion proof to use exising TXO
txo_1 = Output.new(31) # sample
   txo_2 = Output.new(32) # sample
   txo_3 = Output.new(33) # sample
   mmr = PedersenMMR()
   mmr.append(txo_1.hh)
   mmr.append(txo_2.hh)
   mmr.append(txo_3.hh)
   inclusionproofoftxo1 = mmr.getinclusionproof(1)
   zkinclusionproof = inclusionproofoftxo1.zkproof(txo1.r, txo_1.v)

From Pedersen MMR, get an inclusion proof for the item to use as an input txo. It will return an inclusion proof that the current root definitely includes the given spent tag(nullifier). Using this zk inclusion proof, we can sever the link between the input TXOs and output TXOs!

  • Make a send request
# Build transaction first
   tx_send = TxSend.builder(). \
               value(valuetosend). \
               fee(feeforrelayer). \
               inputtxo(inputtxo1, zkinclusionproof1). \
               inputtxo(inputtxo2, zkinclusionproof2). \
               changetxo(changetxo). \
               metadata(addressoferc20, expiration_height). \
               sigsalt(sendersig_salt). \
               build()
   serializedrequest = txsend.serialize() # returns bytes
inputtxo2 and inclusionproof2 can be None. It is just an option to use 2 input TXOs for a transaction. And sendersigsalt is a random number in the Jubjub field for Schnorr signature.
  • Make a response against the request
deserializedrequest = Request.deserialize(serializedrequest)
   tx_receive = TxReceive.builder(). \
       request(deserialized_request). \
       outputtxo(outputtxo). \
       sigsalt(receiversig_salt). \
       build()
   serializedresponse = txreceive.response.serialize()
For a given send request, the recipient should make an own TXO and a Schnorr signature to receive the transaction. Python library will automatically include the range proof for that given output TXO.
  • How to make a transaction? Just merge them!
response = Response.deserialize(serialized_response)
   transaction = tx_send.merge(response)
Sender can complete to make the transaction by merging the request and response. And the Schnorr signature will do a role of receipt for the transaction.
  • Make the roll up proof
current_root = copy.deepcopy(mmr.root)
   current_width = copy.deepcopy(mmr.width)
   current_peaks = copy.deepcopy(mmr.peaks)
   mmr = PedersenMMR.frompeaks(16, currentpeaks)
   itemstoupdate = [
       txo_1.hh,
       txo_2.hh,
       txo_3.hh,
       txo_4.hh,
   ]
   for item in itemstoupdate:
       mmr.append(item)
   new_root = mmr.root
   proof = PedersenMMR.zkrollupproof(currentroot, currentwidth, currentpeaks, itemstoupdate, new_root)
Relayers can aggregate transactions and make a roll up request. Metadata includes the ERC20 address & expiration height. If the submission does not satisfy correct ERC20 address and expiration, the contract will not the tx and roll up request.

How to generate ZKP manually?

You can also use docker containers to generate some proofs manually. Python library also uses those docker containers.

ex)

[Command example]
docker run -e args="3 3 3" ethereum934/zk-range-proof

[List of proof generator containers]

  • ethereum934/zk-deposit
- public: [tag, v] - private: [r] - circuit: circuits/zkDeposit.zok
  • ethereum934/zk-range-proof
- public: [y] - private: [r, v] - circuit: circuits/zkRangeProof.zok
  • ethereum934/zk-mimblewimble
- public: [fee, metadata, tag1, tag2, output[2], change[2], sigPoint[2]] - private: [excess[2], sigScalar[2], inputR1, inputR2, inputV1, inputV2] - circuit: circuits/zkMimblewimble.zok
  • ethereum934/zk-mmr-inclusion
- public: [root, tag] - private: [xPeaks[16], yPeaks[16], position, r, v, xSiblings[16], ySiblings[16]] - circuit: circuits/mmr/zkMMRInclusion.zok
  • ethereum934/zk-roll-up-1
- public: [root, width, item[2], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp1.zok
  • ethereum934/zk-roll-up-2
- public: [root, width, xItems[2], yItems[2], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp2.zok
  • ethereum934/zk-roll-up-4
- public: [root, width, xItems[4], yItems[4], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp4.zok
  • ethereum934/zk-roll-up-8
- public: [root, width, xItems[8], yItems[8], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp8.zok
  • ethereum934/zk-roll-up-16
- public: [root, width, xItems[16], yItems[16], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp16.zok
  • ethereum934/zk-roll-up-32
- public: [root, width, xItems[32], yItems[32], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp32.zok
  • ethereum934/zk-roll-up-64
- public: [root, width, xItems[64], yItems[64], newRoot] - private: [xPeaks[16], yPeaks[16]] - circuit: circuits/mmr/zkRollUp64.zok
  • ethereum934/zk-withdraw
- public: [root, tag, v] - private: [r, xPeaks[16], yPeaks[16], position, xSiblings[16], ySiblings[16]] - circuit: circuits/zkWithdraw.zok

Performance

Test machine: Ryzen1700 (3GHz 8 Core) + DDR4 32Gb

Roll up performance

| | Gas(Avg) | Gas per tx | Maximum TPS | | ------------------------ | --------- | ---------- | ------------- | | Roll up 1 tx | 3,859,179 | 3,859,179 | 0.17 tx / sec | | Roll up 2 tx | 6,645,227 | 3,322,613 | 0.20 tx / sec | | Optimistic roll up 16 tx | 2,492,927 | 155,807 | 4.25 tx / sec | | Optimistic roll up 32 tx | 4,694,516 | 146,703 | 4.53 tx / sec |

Circuit performance

| Circuits | Constraint points | Gas consumption | Proof generation time | | ----------------------------- | ----------------- | --------------- | --------------------- | | Deposit proof | 29,140 | 612,273 | 3 seconds | | Withdraw proof | 588,910 | 658,043 | 3.5 seconds | | Range proof | 19,679 | 568,232 | 2 seconds | | MMR Inclusion Proof | 399,644 | 613,809 | 24 seconds | | Mimblewimble Proof | 141,552 | 975,399 | 9 seconds | | MMR Roll up 2 items (1 txs) | 644,957 | 1,392,269 | 1m 47s | | MMR Roll up 4 items (2 txs) | 968,099 | 1,392,269 | 1m 47s | | MMR Roll up 8 items (4 txs) | 1,614,383 | 1,392,269 | 1m 47s | | MMR Roll up 16 items (8 txs) | 2,906,951 | 2,127,267 | 3m 19s | | MMR Roll up 32 items (16 txs) | 5,492,087 | 3,597,531 | 7m 20s | | MMR Roll up 64 items (32 txs) | 10,662,359 | 6,541,946 | 17m 30s |

Contract: Ethereum934
    deposit()
      โœ“ Deposit ERC20 and create the first coinbase. (676677 gas)
      โœ“ Deposit ERC20 and create the second coinbase. (661549 gas)
    rollUp()
      โœ“ Round 1: roll up 2 Mimblewimble txs spending 1 coinbase for each. (5288641 gas)
      โœ“ Round 2: roll up 2 Mimblewimble txs spending 2 hidden TXOs and 1 hidden TXO. (7047862 gas)
      โœ“ Round 3: roll up 2 Mimblewimble txs spending 2 hidden TXOs for each. (7663886 gas)
      โœ“ Round 4: roll up 1 Mimblewimble tx spending 1 hidden TXO. (3566770 gas)
      โœ“ Round 5: roll up 1 Mimblewimble tx spending 2 hidden TXOs. (4182980 gas)
    optimisticRollUp()
      โœ“ Round 6: optimistic roll up 4 Mimblewimble transactions. (848388 gas)
      โœ“ Round 7: optimistic roll up 8 Mimblewimble transactions. (1396853 gas)
      โœ“ Round 8: optimistic roll up 16 Mimblewimble transactions. (2493375 gas)
      โœ“ Round 9: optimistic roll up 32 Mimblewimble transactions. (4694516 gas)
    withdraw()
      โœ“ should prevent double spending. (46432 gas)
      โœ“ should withdraw ERC20 with zk proof spending a hidden TXO. (715083 gas)

Contract: ZkInterfaces โœ“ Deposit proof (612273 gas) โœ“ Range proof (568232 gas) โœ“ Inclusion proof (613809 gas) โœ“ Mimblewimble proof (975399 gas) โœ“ Roll Up 2 items to the Pedersen Merkle Mountain Range (841457 gas) โœ“ Roll Up 4 items to the Pedersen Merkle Mountain Range (1023228 gas) โœ“ Roll Up 8 items to the Pedersen Merkle Mountain Range (1392269 gas) โœ“ Roll Up 16 items to the Pedersen Merkle Mountain Range (2127267 gas) โœ“ Roll Up 32 items to the Pedersen Merkle Mountain Range (3597531 gas) โœ“ Roll Up 64 items to the Pedersen Merkle Mountain Range (6541946 gas) โœ“ Withdraw proof (658043 gas)

How to contribute

Export verifier contracts for a circuit
  • Export verifier using an existing docker image.
docker run --name mw-proof-generator ethereum934/zk-mimblewimble /bin/bash -c "./zokrates export-verifier"
   docker cp mw-proof-generator:/home/zokrates/verifier.sol contracts/generated/MimblewimbleVerifier.sol
  • Export updated verifier with building a new image.
# Specify the circuit path to compile and export the verifier contract
   make verifier circuit=YOURCIRCUITPATH

# Specify the output path make verifier circuit=YOURCIRCUITPATH output=MyVerifier.sol

Update dataset for solidity test
python sample.py
mv build/*.json test/dataset/ethereum934/
๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท ethereum934/eth-mimblewimble ยท Updated daily from GitHub