/zclean

An implementation of ZCash, private (ie shieldable) utxo-based cryptocurrency including the ability to 'colour' coins while transactions remain private

Primary LanguageOCaml

ZClean

Ref papers:

Concept

Goal

Making a very rough reimplementation of zero-cash like, adding a feature that coins are tainted (with a bit), and that while transferring in zero-knowledge we also prove that the taint is preserved. We only do shielded transactions, and everything has value 1. The state of the blockchain is a merkle tree containing commitements and a list of nullifier.

We will be using Snarky (an explanation of the idea behind Snarky is here )

Components to the blockchain peer + wallet:

  • JSON API
  • MT server
  • Snarky Circuit
  • the blockchain, on a Redis list
  • a wallet with the secrets necessary for the peer to spend the notes
  • a config with the port list

Adding a block(transferring something):

  • I want to transfer a note, I ask my peer to spend it by giving him the neccessary witness informations (aka I use my client, similar to using a full bitcoin node as a wallet) and he creates his own committement.
  • it generates the necessary ZKproofs
  • sends that to the receiver peer
  • the receiver verify all proofs and
    • if successful broadcast it to the network
    • else do nothing/reject
  • if it's accepted, the blockchain is now one block larger

### Rules

  • start with a mktree, containing commitement of the type H(r,b).
  • utxo with 1 in 1 out, no values(or v = 1)
  • to transfer, share a zk with the person you are transferring proving that you know the preimage
  • the nulifier is stored in a dead drop style(file, for now, could be anything, as long as it has the potential to be replaced by an anonymous system)

Block Content:

  • root

  • nullifier

  • new cm

  • proof1: nf is computed correctly

  • proof2: old cm existed in the tree corresponding to root

  • proof3: the flag is consistent (b_old = b_new)

Prover file content:

Prover file transfer_secrets takes a lines of unlabelled values (some are tuples):

  • r - our secret with which to spend this commitment
  • v - the value of the spent commitment (1)
  • flag - the 'clean' flags of the spent commitment, eg 1 or 1155 ( =357*11 )
  • l1_sibling - a tuple of the field value of the sibling of the ancestor on the first level of the Merkel tree, along with the direction in the tree of this value (true/false), eg 34567890098765434567,false
  • l2_sibling - " " second level below root
  • l3_sibling - " " third level below root, ie the sibling of our commitment
  • r' - secret to attach to new commitment
  • v' - the value of the new commitment (1)
  • flag' - the 'clean' flags of the new commitment, should be same as old one, eg 1 or 1155 ( =357*11 )

The discards flag does not work in the current version of snarky and will cause a Match_failure exception due to unexpected file length

  • discards - always 1 in the case that the same flags are carried through

Something like:

3458764513820540928
1
0
7433729977631823532505452732695923773122210654810903057685629706603992852240,true
15288571477637851994690209293501105771757308379597462518238826192746159551987,false
1592181160691996129005532446482721103987578452528597022169202402534844066154,true
999
1
0

Running the code

snarky_cli generate-keys create-coin-commitment.zk --curve Bn128

snarky_cli prove create-coin-commitment.zk 12487572442786697255769734422561910143134627962470873525166458867517877935051 11431946377964512669499131572242457906889915470048508955778605307618910933504

snarky_cli verify create-coin-commitment.zk --proof create-coin-commitment_gen.zkp 12487572442786697255769734422561910143134627962470873525166458867517877935051 11431946377964512669499131572242457906889915470048508955778605307618910933504

NB:

on first run, snarky_cli generate-keys create-coin-commitment.zk --curve Bn128 gives error:

File "create-coin-commitment_gen.ml", line 4, characters 24-53:
Error: Signature mismatch:
       ...
       In module R1CS_constraint_system:
       Values do not match:
         val digest : t -> Core.Md5.t
       is not included in
         val digest : t -> Core_kernel.Md5.t
       File "src/backend_intf.ml", line 91, characters 4-27:
         Expected declaration
       File "src/libsnark.ml", line 945, characters 4-27: Actual declaration

Don't worry - run it again.

Requirements:

  • Docker(to run the blockchain datastore. redis ATM)
  • Ocaml via opam, switched to 4.07.1
  • Snarky installed (good luck with that :D)
  • node.js 12 to run the client and the peer

Starting a demo env

  • run ./install.sh
  • docker-compose up to start the redis instances
  • open 6 term windows
  • in 3 of them, run ./startPeer.sh 0, 1 and 2
  • in 3 of them, run ./startWallet.sh 0, 1 and 2
  • in 1 of them, run ./startExplorer.sh for the block explorer

Usage of the wallet:

  • to transfer a coin, type t 0/1 in a wallet to transfer one coin to a peer
  • to get the balance, type b
  • to check the status, type s

...