Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mimc integration #31

Merged
merged 23 commits into from
Jul 2, 2019
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
64effff
get_var utils moved
riemann89 Jun 20, 2019
860cfb1
moved get_iv functions in circuits-util and squashed get_var/get_zeto
riemann89 Jun 20, 2019
b9a8033
outer comm inherits from mimc_hash
riemann89 Jun 21, 2019
87faf44
mimc7 file renamed, added iv constants and modified GRPC primtives to…
riemann89 Jun 24, 2019
d223ccb
fix input of mimc calls from hex to int
riemann89 Jun 24, 2019
87b5099
modified proto messages for new notes
riemann89 Jun 27, 2019
b61e934
fix constructors of BaseMixer.sol, Groth16Mixer.sol and bit refactori…
riemann89 Jun 27, 2019
47c77e5
small modification of ZethNote and JSInput classes
riemann89 Jun 27, 2019
e70dd00
small changes to the circuits due to the modifications of the ZethNote
riemann89 Jun 27, 2019
9f80fbc
moved trom util and util_api from .cpp .tcc and add conversion functi…
riemann89 Jun 27, 2019
934166a
Update prover server with new circuits/types and CMakelists.txt with …
riemann89 Jun 27, 2019
5cd9bde
fix test of testMiMCHash, add test module in the requirements
riemann89 Jun 27, 2019
b150d36
updated contract cosntructor in the deploying/compiling python utility
riemann89 Jun 27, 2019
e97d5ce
fix outer commitment and removed 0x character from the utility funcions
riemann89 Jun 27, 2019
b667e11
modified Ether and Token tests to work with new contracts
riemann89 Jun 27, 2019
f48ab80
fix rebase
riemann89 Jun 27, 2019
f3d9f66
add missing header in util.hpp
riemann89 Jun 27, 2019
3ee1021
changing Pghr13 interface to work with mimc
rrtoledo Jun 27, 2019
0c6c9e4
fix string to field function
riemann89 Jun 27, 2019
68e2a5f
updating commitment to remove mask and nested, updated types tests an…
rrtoledo Jul 1, 2019
865f17e
adding specific iv for commitments
rrtoledo Jul 1, 2019
81c5486
adding cm iv
rrtoledo Jul 1, 2019
34bcaff
replacing R0 by R ; adding comment
rrtoledo Jul 1, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/prover.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ message ProofInputs {
string root = 1;
repeated JSInput jsInputs = 2; // List of inputs to the JS
repeated ZethNote jsOutputs = 3; // List of output to the JS
string inPubValue = 4; // Hexadecimal string representing a int64
string outPubValue = 5; // Hexadecimal string representing a int64
string inPubValue = 4; // Hexadecimal string representing a 32bytes int
string outPubValue = 5; // Hexadecimal string representing a 32bytes int
}

// We comment this message as the primary input is passed as a json string for now
Expand Down
10 changes: 3 additions & 7 deletions api/util.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ syntax = "proto3";

package proverpkg;

message PackedDigest {
string part1 = 1; // First 253bits of the digest
string part2 = 2; // Last 3bits of the digest
}

message ZethNote {
string aPK = 1;
string value = 2; // Hexadecimal string representing a int64
string value = 2;
string rho = 3;
string trapR = 4;
string trapR0 = 4;
string trapR1 = 5;
rrtoledo marked this conversation as resolved.
Show resolved Hide resolved
}

message JSInput {
Expand Down
1 change: 1 addition & 0 deletions pyClient/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ toolz==0.9.0
urllib3==1.24.2
web3==4.8.2
websockets==6.0
pysha3==1.0.2
2 changes: 2 additions & 0 deletions pyClient/testERCTokenMixing.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ def mint_token(token_instance, spender_address, deployer_address, token_amount):
print("[INFO] 3. VK written, deploying the smart contracts...")
token_interface = compile_token()
(verifier_interface, mixer_interface) = zethContracts.compile_contracts(zksnark)
hasher_interface, _ = zethContracts.compile_util_contracts()
token_instance = deploy_token(deployer_eth_address, 4000000)
(mixer_instance, initial_root) = zethContracts.deploy_contracts(
mk_tree_depth,
verifier_interface,
mixer_interface,
hasher_interface,
deployer_eth_address,
4000000,
token_instance.address, # We mix Ether in this test, so we set the addr of the ERC20 contract to be 0x0
Expand Down
5 changes: 4 additions & 1 deletion pyClient/testEtherMixing.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ def get_merkle_tree(mixer_instance):

print("[INFO] 3. VK written, deploying the smart contracts...")
(verifier_interface, mixer_interface) = zethContracts.compile_contracts(zksnark)
hasher_interface, _ = zethContracts.compile_util_contracts()
(mixer_instance, initial_root) = zethContracts.deploy_contracts(
mk_tree_depth,
verifier_interface,
mixer_interface,
hasher_interface,
deployer_eth_address,
4000000,
"0x0000000000000000000000000000000000000000", # We mix Ether in this test, so we set the addr of the ERC20 contract to be 0x0
Expand All @@ -73,7 +75,6 @@ def get_merkle_tree(mixer_instance):
charlie_eth_address,
mixer_instance.address
)

# Bob deposits 4ETH split in 2 notes of denominations of 2ETh and 2ETH on the mixer
result_deposit_bob_to_bob = zethTest.bob_deposit(
test_grpc_endpoint,
Expand All @@ -84,6 +85,7 @@ def get_merkle_tree(mixer_instance):
mk_tree_depth,
zksnark
)

cm_address_bob_to_bob1 = result_deposit_bob_to_bob[0]
cm_address_bob_to_bob2 = result_deposit_bob_to_bob[1]
new_merkle_root_bob_to_bob = result_deposit_bob_to_bob[2]
Expand Down Expand Up @@ -113,6 +115,7 @@ def get_merkle_tree(mixer_instance):
# Bob decrypts one of the note he previously received (useless here but useful if the payment came from someone else)
input_note_json = json.loads(zethUtils.decrypt(ciphertext_bob_to_bob1, keystore["Bob"]["AddrSk"]["dk"]))
input_note_bob_to_charlie = zethGRPC.zethNoteObjFromParsed(input_note_json)

# Execution of the transfer
result_transfer_bob_to_charlie = zethTest.bob_to_charlie(
test_grpc_endpoint,
Expand Down
17 changes: 13 additions & 4 deletions pyClient/testMiMCHash.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
iv = 918403109389145570117360101535982733651217667914747213867238065296420114726
out = 15683951496311901749339509118960676303290224812129752890706581988986633412003

# Test cases generated from https://github.com/riemann89/ethsnarks/blob/master/src/utils/mimc_hash_test_cases.cpp
root = 10734222616343366978183290578250016397752183448862818550078506087190022377626
level_1 = 4571162561214823491685468001824923339916598569432941893158208026396444541263
level_2 = 21783731659988531455046720456618223572462885645210824868284396990406188448077
# Test cases generated from https://github.com/riemann89/ethsnarks/blob/master/src/utils/mimc_hash_test_cases.cpp with mt_iv
root = 11716064043359892586827861099037056012854304663991858447116188660975533174593
level_1 = 8830982470254157157072290926830971455574680711064480284113552856555397977780
level_2 = 2689880186515302973494776427415865270938416831401566119966263629471944181012


if __name__ == "__main__":
# MiMC contract unit test
Expand All @@ -36,14 +37,22 @@

# MerkleTreeMiMCHash of depth 3 unit test
tree = zethContracts.getTree(tree_instance)
root_recovered = zethContracts.getRoot(tree_instance)
for i in range(7,15):
assert int.from_bytes(tree[i], byteorder="big") == 0
"MerkleTree Error"

for i in range(3, 7):
print("LEVEL 2:"+str(int.from_bytes(tree[i], byteorder="big")))
print(i)
assert int.from_bytes(tree[i], byteorder="big") == level_2

for i in range(1, 3):
print("LEVEL 1:"+str(int.from_bytes(tree[i], byteorder="big")))
assert int.from_bytes(tree[i], byteorder="big") == level_1

print("ROOT:"+str(int.from_bytes(tree[0], byteorder="big")))
assert int.from_bytes(tree[0], byteorder="big") == root

print("ROOT RECOVERED:"+str(int.from_bytes(root_recovered, byteorder="big")))
assert int.from_bytes(root_recovered, byteorder="big") == root
7 changes: 7 additions & 0 deletions pyClient/zethConstants.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@

# Merkle tree depth
ZETH_MERKLE_TREE_DEPTH = 4

# MiMC constants
ZETH_MIMC_PRIME = 21888242871839275222246405745257275088548364400416034343698204186575808495617
ZETH_MIMC_IV_MT = 14220067918847996031108144435763672811050758065945364308986253046354060608451
ZETH_MIMC_IV_ADD = 7655352919458297598499032567765357605187604397960652899494713742188031353302
ZETH_MIMC_IV_NF = 38594890471543702135425523844252992926779387339253565328142220201141984377400
ZETH_MIMC_IV_PK = 20715549373167656640519441333099474211916836972862576858009333815040496998894
18 changes: 12 additions & 6 deletions pyClient/zethContracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,14 @@ def deploy_pghr13_verifier(vk, verifier, deployer_address, deployment_gas):

# Common function to deploy a mixer contract
# Returns the mixer and the initial merkle root of the commitment tree
def deploy_mixer(verifier_address, mixer_interface, mk_tree_depth, deployer_address, deployment_gas, token_address):
def deploy_mixer(verifier_address, mixer_interface, mk_tree_depth, deployer_address, deployment_gas, token_address, hasher_address):
# Deploy the Mixer contract once the Verifier is successfully deployed
mixer = w3.eth.contract(abi=mixer_interface['abi'], bytecode=mixer_interface['bin'])
tx_hash = mixer.constructor(
verifier_address = verifier_address,
mk_depth = mk_tree_depth,
token_address = token_address
token_address = token_address,
hasher_address = hasher_address
).transact({'from': deployer_address, 'gas': deployment_gas})
# Get tx receipt to get Mixer contract address
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash, 10000)
Expand Down Expand Up @@ -119,14 +120,15 @@ def deploy_groth16_verifier(vk, verifier, deployer_address, deployment_gas):
verifier_address = tx_receipt['contractAddress']
return verifier_address

def deploy_groth16_contracts(vk_json, mk_tree_depth, verifier, mixer_interface, deployer_address, deployment_gas, token_address):
def deploy_groth16_contracts(vk_json, mk_tree_depth, verifier, mixer_interface, hasher_interface, deployer_address, deployment_gas, token_address):
verifier_address = deploy_groth16_verifier(vk_json, verifier, deployer_address, deployment_gas)
return deploy_mixer(verifier_address, mixer_interface, mk_tree_depth, deployer_address, deployment_gas, token_address)
_, hasher_address = deploy_mimc_contract(hasher_interface)
return deploy_mixer(verifier_address, mixer_interface, mk_tree_depth, deployer_address, deployment_gas, token_address, hasher_address)

# Deploy the mixer contract with the given merkle tree depth
# and returns an instance of the mixer along with the initial merkle tree
# root to use for the first zero knowledge payments
def deploy_contracts(mk_tree_depth, verifier_interface, mixer_interface, deployer_address, deployment_gas, token_address, zksnark):
def deploy_contracts(mk_tree_depth, verifier_interface, mixer_interface, hasher_interface, deployer_address, deployment_gas, token_address, zksnark):
setup_dir = os.environ['ZETH_TRUSTED_SETUP_DIR']
vk_json = os.path.join(setup_dir, "vk.json")
with open(vk_json) as json_data:
Expand All @@ -137,7 +139,7 @@ def deploy_contracts(mk_tree_depth, verifier_interface, mixer_interface, deploye
if zksnark == constants.PGHR13_ZKSNARK:
return deploy_pghr13_contracts(vk, mk_tree_depth, verifier, mixer_interface, deployer_address, deployment_gas, token_address)
elif zksnark == constants.GROTH16_ZKSNARK:
return deploy_groth16_contracts(vk, mk_tree_depth, verifier, mixer_interface, deployer_address, deployment_gas, token_address)
return deploy_groth16_contracts(vk, mk_tree_depth, verifier, mixer_interface, hasher_interface, deployer_address, deployment_gas, token_address)
else:
return sys.exit(errors.SNARK_NOT_SUPPORTED)

Expand Down Expand Up @@ -278,3 +280,7 @@ def mimcHash(instance, m, iv):
# Return MimC merklee tree
def getTree(instance):
return instance.functions.getTree().call()

# Return MimC merklee tree
def getRoot(instance):
return instance.functions.getRoot().call()
103 changes: 59 additions & 44 deletions pyClient/zethGRPC.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
import zethConstants as constants
import zethErrors as errors

# Import MiMC hash and constants
from zethMimc import MiMC7
from zethConstants import ZETH_MIMC_IV_MT, ZETH_MIMC_IV_NF, ZETH_MIMC_IV_ADD

# Fetch the verification key from the proving service
def getVerificationKey(grpcEndpoint):
with grpc.insecure_channel(grpcEndpoint) as channel:
Expand All @@ -44,10 +48,12 @@ def hex2int(elements):

def noteRandomness():
rand_rho = bytes(Random.get_random_bytes(32)).hex()
rand_trapR = bytes(Random.get_random_bytes(48)).hex()
rand_trapR0 = bytes(Random.get_random_bytes(32)).hex()
rrtoledo marked this conversation as resolved.
Show resolved Hide resolved
rand_trapR1 = bytes(Random.get_random_bytes(32)).hex()
rrtoledo marked this conversation as resolved.
Show resolved Hide resolved
randomness = {
"rho": rand_rho,
"trapR": rand_trapR
"trapR0": rand_trapR0,
"trapR1": rand_trapR1
}
return randomness

Expand All @@ -57,7 +63,8 @@ def createZethNote(randomness, recipientApk, value):
aPK=recipientApk,
value=value,
rho=randomness["rho"],
trapR=randomness["trapR"]
trapR0=randomness["trapR0"],
trapR1=randomness["trapR1"]
)
return note

Expand All @@ -66,7 +73,8 @@ def parseZethNote(zethNoteGRPCObj):
"aPK": zethNoteGRPCObj.aPK,
"value": zethNoteGRPCObj.value,
"rho": zethNoteGRPCObj.rho,
"trapR": zethNoteGRPCObj.trapR,
"trapR0": zethNoteGRPCObj.trapR0,
"trapR1": zethNoteGRPCObj.trapR1,
}
return noteJSON

Expand All @@ -75,7 +83,8 @@ def zethNoteObjFromParsed(parsedZethNote):
aPK=parsedZethNote["aPK"],
value=parsedZethNote["value"],
rho=parsedZethNote["rho"],
trapR=parsedZethNote["trapR"]
trapR0=parsedZethNote["trapR0"],
trapR1=parsedZethNote["trapR1"]
)
return note

Expand All @@ -85,57 +94,61 @@ def hexFmt(string):
# Used by the recipient of a payment to recompute the commitment and check the membership in the tree
# to confirm the validity of a payment
def computeCommitment(zethNoteGRPCObj):
# inner_k = sha256(a_pk || rho)
inner_k = hashlib.sha256(
encode_abi(['bytes32', 'bytes32'], (bytes.fromhex(zethNoteGRPCObj.aPK), bytes.fromhex(zethNoteGRPCObj.rho)))
).hexdigest()

# outer_k = sha256(r || [inner_k]_128)
first128InnerComm = inner_k[0:128]
outer_k = hashlib.sha256(
encode_abi(['bytes', 'bytes'], (bytes.fromhex(zethNoteGRPCObj.trapR), bytes.fromhex(first128InnerComm)))
).hexdigest()

# cm = sha256(outer_k || 0^192 || value_v)
frontPad = "000000000000000000000000000000000000000000000000"
cm = hashlib.sha256(
encode_abi(["bytes32", "bytes32"], (bytes.fromhex(outer_k), bytes.fromhex(frontPad + zethNoteGRPCObj.value)))
).hexdigest()
return cm
m = MiMC7()

aPK = int(zethNoteGRPCObj.aPK, 16)
rho = int(zethNoteGRPCObj.rho, 16)
trapR0 = int(zethNoteGRPCObj.trapR0, 16)
rrtoledo marked this conversation as resolved.
Show resolved Hide resolved
trapR1 = int(zethNoteGRPCObj.trapR1, 16)
value = int(zethNoteGRPCObj.value, 16)

# inner_k = MiMCHash(a_pk || rho)
inner_k = m.hash([aPK, rho], ZETH_MIMC_IV_MT)

#outer_k = MiMCHash(r_1, r_0+inner_k)
outer_k = m.hash([trapR1, trapR0+inner_k], ZETH_MIMC_IV_MT)

#cm = MiMCHash(value, outer_k)
cm = m.hash([outer_k, value], ZETH_MIMC_IV_MT)

return hex(cm)[2:]

def hexadecimalDigestToBinaryString(digest):
binary = lambda x: "".join(reversed( [i+j for i,j in zip( *[ ["{0:04b}".format(int(c,16)) for c in reversed("0"+x)][n::2] for n in [1,0]])]))
return binary(digest)

def computeNullifier(zethNote, spendingAuthAsk):
# nf = sha256(a_sk || 01 || [rho]_254)
binaryRho = hexadecimalDigestToBinaryString(zethNote.rho)
first254Rho = binaryRho[0:254]
rightLegBin = "01" + first254Rho
rightLegHex = "{0:0>4X}".format(int(rightLegBin, 2))
print("Compute nullifier")
nullifier = hashlib.sha256(
encode_abi(["bytes32", "bytes32"], [bytes.fromhex(spendingAuthAsk), bytes.fromhex(rightLegHex)])
).hexdigest()
return nullifier
def computeNullifier(zethNote, ask):
m = MiMC7()

rho = int(zethNote.rho, 16)
ask = int(ask, 16)

# nf = MiMCHash(a_sk,rho)
nullifier = m.hash([ask, rho], ZETH_MIMC_IV_NF)


return hex(nullifier)[2:]

# TODO change name since it could be misleading by reading the code: it works well for any number, not only int64
def int64ToHexadecimal(number):
return '{:016x}'.format(number)

def deriveAPK(ask):
# a_pk = sha256(a_sk || 0^256)
zeroes = "0000000000000000000000000000000000000000000000000000000000000000"
a_pk = hashlib.sha256(
encode_abi(["bytes32", "bytes32"], [bytes.fromhex(ask), bytes.fromhex(zeroes)])
).hexdigest()
return a_pk
# apk = MiMCHash(a_sk, 0)
m = MiMC7()

ask = int(ask, 16)

apk = m.hash([ask,0], ZETH_MIMC_IV_ADD)

return hex(apk)[2:]

def generateApkAskKeypair():
a_sk = bytes(Random.get_random_bytes(32)).hex()
a_pk = deriveAPK(a_sk)
ask = bytes(Random.get_random_bytes(32)).hex()
apk = deriveAPK(ask)
keypair = {
"aSK": a_sk,
"aPK": a_pk
"aSK": ask,
"aPK": apk
}
return keypair

Expand Down Expand Up @@ -230,7 +243,6 @@ def parseProofGROTH16(proofObj):
return proofJSON

def parseProof(proofObj, zksnark):
proofJSON = {}
if zksnark == constants.PGHR13_ZKSNARK:
return parseProofPGHR13(proofObj)
elif zksnark == constants.GROTH16_ZKSNARK:
Expand Down Expand Up @@ -271,8 +283,11 @@ def get_proof_joinsplit_2by2(
]

proof_input = makeProofInputs(mk_root, js_inputs, js_outputs, public_in_value, public_out_value)

proof_obj = getProof(grpcEndpoint, proof_input)

proof_json = parseProof(proof_obj, zksnark)

# We return the zeth notes to be able to spend them later
# and the proof used to create them
return (output_note1, output_note2, proof_json)
Loading