Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
scenario.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 # Copyright (c) 2015-2022 Clearmatics Technologies Ltd
4 #
5 # SPDX-License-Identifier: LGPL-3.0+
6 
7 from zeth.core.zeth_address import ZethAddressPub
8 from zeth.core.mixer_client import MixCallDescription, MixParameters, MixResult, \
9  MixerClient, OwnershipKeyPair, JoinsplitSigVerificationKey, ComputeHSigCB, \
10  JoinsplitSigKeyPair, joinsplit_sign, encrypt_notes, \
11  event_args_to_mix_result, get_dummy_input_and_address, compute_h_sig
12 from zeth.core.prover_client import ProverClient
13 from zeth.core.zksnark import IZKSnarkProvider, ExtendedProof
14 from zeth.core import signing
15 from zeth.core.contracts import get_event_logs_from_tx_receipt
16 from zeth.core.merkle_tree import MerkleTree
17 from zeth.core.utils import EtherValue
18 from zeth.api.zeth_messages_pb2 import ZethNote
19 from test_commands import mock
20 
21 from os import urandom
22 from web3 import Web3 # type: ignore
23 from typing import List, Tuple, Optional, Any
24 
25 ZERO_UNITS_HEX = "0000000000000000"
26 BOB_DEPOSIT_ETH = 200
27 BOB_SPLIT_1_ETH = 100
28 BOB_SPLIT_2_ETH = 100
29 
30 BOB_TO_CHARLIE_ETH = 50
31 BOB_TO_CHARLIE_CHANGE_ETH = BOB_SPLIT_1_ETH - BOB_TO_CHARLIE_ETH
32 
33 CHARLIE_WITHDRAW_ETH = 10.5
34 CHARLIE_WITHDRAW_CHANGE_ETH = 39.5
35 
36 
37 def dump_merkle_tree(mk_tree: List[bytes]) -> None:
38  print("[DEBUG] Displaying the Merkle tree of commitments: ")
39  for node in mk_tree:
40  print("Node: " + Web3.toHex(node)[2:])
41 
42 
44  mixer_instance: Any,
45  tx_receipt: Any) -> MixResult:
46  """
47  Get the logs data associated with this mixing
48  """
49  log_mix_events = \
50  get_event_logs_from_tx_receipt(mixer_instance, "LogMix", tx_receipt)
51  mix_results = [event_args_to_mix_result(ev.args) for ev in log_mix_events]
52  return mix_results[0]
53 
54 
56  zeth_client: MixerClient,
57  mk_tree: MerkleTree,
58  tx_hash: str) -> MixResult:
59  tx_receipt = zeth_client.web3.eth.waitForTransactionReceipt(tx_hash, 10000)
60  result = parse_mix_call(zeth_client.mixer_instance, tx_receipt)
61  for out_ev in result.output_events:
62  mk_tree.insert(out_ev.commitment)
63 
64  if mk_tree.recompute_root() != result.new_merkle_root:
65  raise Exception("Merkle root mismatch between log and local tree")
66  return result
67 
68 
70  zeth_client: MixerClient,
71  prover_client: ProverClient,
72  mk_tree: MerkleTree,
73  sender_ownership_keypair: OwnershipKeyPair,
74  inputs: List[Tuple[int, ZethNote]],
75  outputs: List[Tuple[ZethAddressPub, EtherValue]],
76  v_in: EtherValue,
77  v_out: EtherValue,
78  compute_h_sig_cb: Optional[ComputeHSigCB] = None
79 ) -> Tuple[ZethNote, ZethNote, ExtendedProof, List[int], JoinsplitSigKeyPair]:
80  """
81  Manually create the components required for MixParameters. The tests below
82  manipulate these to create custom MixParameters as part of attacks.
83  """
84  mix_call_desc = MixCallDescription(
85  mk_tree,
86  sender_ownership_keypair,
87  inputs,
88  outputs,
89  v_in,
90  v_out,
91  compute_h_sig_cb)
92  prover_inputs, signing_keypair = zeth_client.create_prover_inputs(
93  mix_call_desc)
94  ext_proof, public_data = prover_client.get_proof(prover_inputs)
95  return (
96  prover_inputs.js_outputs[0],
97  prover_inputs.js_outputs[1],
98  ext_proof,
99  public_data,
100  signing_keypair)
101 
102 
104  zeth_client: MixerClient,
105  prover_client: ProverClient,
106  mk_tree: MerkleTree,
107  bob_eth_address: str,
108  keystore: mock.KeyStore,
109  tx_value: Optional[EtherValue] = None) -> MixResult:
110  print(
111  f"=== Bob deposits {BOB_DEPOSIT_ETH} ETH for himself and splits into " +
112  f"note1: {BOB_SPLIT_1_ETH}ETH, note2: {BOB_SPLIT_2_ETH}ETH ===")
113 
114  bob_js_keypair = keystore["Bob"]
115  bob_addr = keystore["Bob"].addr_pk
116 
117  outputs = [
118  (bob_addr, EtherValue(BOB_SPLIT_1_ETH)),
119  (bob_addr, EtherValue(BOB_SPLIT_2_ETH)),
120  ]
121 
122  tx_hash = zeth_client.deposit(
123  prover_client,
124  mk_tree,
125  bob_js_keypair,
126  bob_eth_address,
127  None,
128  EtherValue(BOB_DEPOSIT_ETH),
129  outputs,
130  tx_value)
131  return wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
132 
133 
135  zeth_client: MixerClient,
136  prover_client: ProverClient,
137  mk_tree: MerkleTree,
138  input1: Tuple[int, ZethNote],
139  bob_eth_address: str,
140  keystore: mock.KeyStore) -> MixResult:
141  print(
142  f"=== Bob transfers {BOB_TO_CHARLIE_ETH}ETH to Charlie from his funds " +
143  "on the mixer ===")
144 
145  bob_ask = keystore["Bob"].addr_sk.a_sk
146  charlie_addr = keystore["Charlie"].addr_pk
147  bob_addr = keystore["Bob"].addr_pk
148 
149  # Coin for Bob (change)
150  output0 = (bob_addr, EtherValue(BOB_TO_CHARLIE_ETH))
151  # Coin for Charlie
152  output1 = (charlie_addr, EtherValue(BOB_TO_CHARLIE_CHANGE_ETH))
153 
154  # Send the tx
155  tx_hash = zeth_client.joinsplit(
156  prover_client,
157  mk_tree,
158  OwnershipKeyPair(bob_ask, bob_addr.a_pk),
159  bob_eth_address,
160  None,
161  [input1],
162  [output0, output1],
163  EtherValue(0),
164  EtherValue(0),
165  EtherValue(1, 'wei'))
166  return wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
167 
168 
170  zeth_client: MixerClient,
171  prover_client: ProverClient,
172  mk_tree: MerkleTree,
173  input1: Tuple[int, ZethNote],
174  charlie_eth_address: str,
175  keystore: mock.KeyStore) -> MixResult:
176  print(
177  f" === Charlie withdraws {CHARLIE_WITHDRAW_ETH}ETH from his funds " +
178  "on the Mixer ===")
179 
180  charlie_pk = keystore["Charlie"].addr_pk
181  charlie_apk = charlie_pk.a_pk
182  charlie_ask = keystore["Charlie"].addr_sk.a_sk
183  charlie_ownership_key = \
184  OwnershipKeyPair(charlie_ask, charlie_apk)
185 
186  tx_hash = zeth_client.joinsplit(
187  prover_client,
188  mk_tree,
189  charlie_ownership_key,
190  charlie_eth_address,
191  None,
192  [input1],
193  [(charlie_pk, EtherValue(CHARLIE_WITHDRAW_CHANGE_ETH))],
194  EtherValue(0),
195  EtherValue(CHARLIE_WITHDRAW_ETH),
196  EtherValue(1, 'wei'))
197  return wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
198 
199 
201  zeth_client: MixerClient,
202  prover_client: ProverClient,
203  zksnark: IZKSnarkProvider,
204  mk_tree: MerkleTree,
205  input1: Tuple[int, ZethNote],
206  charlie_eth_address: str,
207  keystore: mock.KeyStore) -> MixResult:
208  """
209  Charlie tries to carry out a double spending by modifying the value of the
210  nullifier of the previous payment
211  """
212  pp = zeth_client.prover_config.pairing_parameters
213  scalar_field_mod = pp.scalar_field_mod()
214  scalar_field_capacity = pp.scalar_field_capacity
215 
216  print(
217  f" === Charlie attempts to withdraw {CHARLIE_WITHDRAW_ETH}ETH once " +
218  "more (double spend) one of his note on the Mixer ===")
219 
220  charlie_addr = keystore["Charlie"]
221  charlie_apk = charlie_addr.addr_pk.a_pk
222 
223  # Create the an additional dummy input for the MixerClient
224  input2 = get_dummy_input_and_address(charlie_apk)
225 
226  note1_value = EtherValue(CHARLIE_WITHDRAW_CHANGE_ETH)
227  v_out = EtherValue(CHARLIE_WITHDRAW_ETH)
228 
229  # ### ATTACK BLOCK
230  # Add malicious nullifiers: we reuse old nullifiers to double spend by
231  # adding $r$ to them so that they have the same value as before in Z_r,
232  # and so the zksnark verification passes, but have different values in
233  # {0;1}^256 so that they appear different to the contract.
234  # See: https://github.com/clearmatics/zeth/issues/38
235 
236  attack_primary_input3: int = 0
237  attack_primary_input4: int = 0
238 
239  def compute_h_sig_attack_nf(
240  nfs: List[bytes],
241  sign_vk: JoinsplitSigVerificationKey) -> bytes:
242  # We disassemble the nfs to get the formatting of the primary inputs
243  assert len(nfs) == 2
244  nf0 = nfs[0]
245  nf1 = nfs[1]
246  input_nullifier0 = nf0.hex()
247  input_nullifier1 = nf1.hex()
248  nf0_rev = "{0:0256b}".format(int(input_nullifier0, 16))
249  primary_input3_bits = nf0_rev[:scalar_field_capacity]
250  primary_input3_res_bits = nf0_rev[scalar_field_capacity:]
251  nf1_rev = "{0:0256b}".format(int(input_nullifier1, 16))
252  primary_input4_bits = nf1_rev[:scalar_field_capacity]
253  primary_input4_res_bits = nf1_rev[scalar_field_capacity:]
254 
255  # We perform the attack, recoding the modified public input values
256  nonlocal attack_primary_input3
257  nonlocal attack_primary_input4
258  attack_primary_input3 = int(primary_input3_bits, 2) + scalar_field_mod
259  attack_primary_input4 = int(primary_input4_bits, 2) + scalar_field_mod
260 
261  # We reassemble the nfs
262  attack_primary_input3_bits = "{0:0256b}".format(attack_primary_input3)
263  attack_nf0_bits = attack_primary_input3_bits[
264  len(attack_primary_input3_bits) - scalar_field_capacity:] +\
265  primary_input3_res_bits
266  attack_nf0 = "{0:064x}".format(int(attack_nf0_bits, 2))
267  attack_primary_input4_bits = "{0:0256b}".format(attack_primary_input4)
268  attack_nf1_bits = attack_primary_input4_bits[
269  len(attack_primary_input4_bits) - scalar_field_capacity:] +\
270  primary_input4_res_bits
271  attack_nf1 = "{0:064x}".format(int(attack_nf1_bits, 2))
272  return compute_h_sig(
273  [bytes.fromhex(attack_nf0), bytes.fromhex(attack_nf1)], sign_vk)
274 
275  output_note1, output_note2, proof, public_data, signing_keypair = \
277  zeth_client,
278  prover_client,
279  mk_tree,
280  keystore["Charlie"].ownership_keypair(), # sender
281  [input1, input2],
282  [(charlie_addr.addr_pk, note1_value),
283  (charlie_addr.addr_pk, EtherValue(0))],
284  EtherValue(0),
285  v_out,
286  compute_h_sig_attack_nf)
287 
288  # Update the primary inputs to the modified nullifiers, since libsnark
289  # overwrites them with values in Z_p
290 
291  assert attack_primary_input3 != 0
292  assert attack_primary_input4 != 0
293 
294  print("proof = ", proof)
295  print("public_data[3] = ", public_data[3])
296  print("public_data[4] = ", public_data[4])
297  public_data[3] = attack_primary_input3
298  public_data[4] = attack_primary_input4
299  # ### ATTACK BLOCK
300 
301  # construct pk object from bytes
302  pk_charlie = keystore["Charlie"].addr_pk.k_pk
303 
304  # encrypt the coins
305  ciphertexts = encrypt_notes([
306  (output_note1, pk_charlie),
307  (output_note2, pk_charlie)])
308 
309  # Compute the joinSplit signature
310  joinsplit_sig_charlie = joinsplit_sign(
311  zksnark,
312  pp,
313  signing_keypair,
314  charlie_eth_address,
315  ciphertexts,
316  proof,
317  public_data)
318 
319  mix_params = MixParameters(
320  proof,
321  public_data,
322  signing_keypair.vk,
323  joinsplit_sig_charlie,
324  ciphertexts)
325 
326  tx_hash = zeth_client.mix(
327  mix_params,
328  charlie_eth_address,
329  # Pay an arbitrary amount (1 wei here) that will be refunded since the
330  # `mix` function is payable
331  None,
332  EtherValue(1, 'wei'))
333  return wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
334 
335 
337  zeth_client: MixerClient,
338  prover_client: ProverClient,
339  zksnark: IZKSnarkProvider,
340  mk_tree: MerkleTree,
341  bob_eth_address: str,
342  charlie_eth_address: str,
343  keystore: mock.KeyStore) -> MixResult:
344  """
345  Charlie tries to break transaction malleability and corrupt the coins
346  bob is sending in a transaction
347  She does so by intercepting bob's transaction and either:
348  - case 1: replacing the ciphertexts (or sender_eph_pk) by garbage/arbitrary
349  data
350  - case 2: replacing the ciphertexts by garbage/arbitrary data and using a
351  new OT-signature
352  - case 3: Charlie replays the mix call of Bob, to try to receive the vout
353  Both attacks should fail,
354  - case 1: the signature check should fail, else Charlie broke UF-CMA of the
355  OT signature
356  - case 2: the h_sig/vk verification should fail, as h_sig is not a function
357  of vk any longer
358  - case 3: the signature check should fail, because `msg.sender` will no match
359  the value used in the mix parameters (Bob's Ethereum Address).
360  NB. If the adversary were to corrupt the ciphertexts (or the encryption key),
361  replace the OT-signature by a new one and modify the h_sig accordingly so that
362  the check on the signature verification (key h_sig/vk) passes, the proof would
363  not verify, which is why we do not test this case.
364  """
365  print(
366  f"=== Bob deposits {BOB_DEPOSIT_ETH} ETH for himself and split into " +
367  f"note1: {BOB_SPLIT_1_ETH}ETH, note2: {BOB_SPLIT_2_ETH}ETH " +
368  "but Charlie attempts to corrupt the transaction ===")
369  bob_addr_pk = keystore["Bob"]
370  bob_apk = bob_addr_pk.addr_pk.a_pk
371 
372  # Get pairing parameters
373  pp = prover_client.get_configuration().pairing_parameters
374 
375  # Create the JoinSplit dummy inputs for the deposit
376  input1 = get_dummy_input_and_address(bob_apk)
377  input2 = get_dummy_input_and_address(bob_apk)
378 
379  note1_value = EtherValue(BOB_SPLIT_1_ETH)
380  note2_value = EtherValue(BOB_SPLIT_2_ETH)
381 
382  v_in = EtherValue(BOB_DEPOSIT_ETH)
383 
384  output_note1, output_note2, proof, public_data, joinsplit_keypair = \
386  zeth_client,
387  prover_client,
388  mk_tree,
389  keystore["Bob"].ownership_keypair(),
390  [input1, input2],
391  [(bob_addr_pk.addr_pk, note1_value),
392  (bob_addr_pk.addr_pk, note2_value)],
393  v_in,
394  EtherValue(0)) # v_out
395 
396  # Encrypt the coins to bob
397  pk_bob = keystore["Bob"].addr_pk.k_pk
398  ciphertexts = encrypt_notes([
399  (output_note1, pk_bob),
400  (output_note2, pk_bob)])
401 
402  # ### ATTACK BLOCK
403  # Charlie intercepts Bob's deposit, corrupts it and
404  # sends her transaction before Bob's transaction is accepted
405 
406  # Case 1: replacing the ciphertexts by garbage/arbitrary data
407  # Corrupt the ciphertexts
408  # (another way would have been to overwrite sender_eph_pk)
409  fake_ciphertext0 = urandom(32)
410  fake_ciphertext1 = urandom(32)
411 
412  result_corrupt1 = None
413  try:
414  joinsplit_sig_charlie = joinsplit_sign(
415  zksnark,
416  pp,
417  joinsplit_keypair,
418  charlie_eth_address,
419  ciphertexts,
420  proof,
421  public_data)
422 
423  mix_params = MixParameters(
424  proof,
425  public_data,
426  joinsplit_keypair.vk,
427  joinsplit_sig_charlie,
428  [fake_ciphertext0, fake_ciphertext1])
429  tx_hash = zeth_client.mix(
430  mix_params,
431  charlie_eth_address,
432  None,
433  EtherValue(BOB_DEPOSIT_ETH))
434  result_corrupt1 = \
435  wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
436  except Exception as e:
437  print(
438  "Charlie's first corruption attempt" +
439  f" successfully rejected! (msg: {e})"
440  )
441  assert(result_corrupt1 is None), \
442  "Charlie managed to corrupt Bob's deposit the first time!"
443  print("")
444 
445  # Case 2: replacing the ciphertexts by garbage/arbitrary data and
446  # using a new OT-signature
447  # Corrupt the ciphertexts
448  fake_ciphertext0 = urandom(32)
449  fake_ciphertext1 = urandom(32)
450  new_joinsplit_keypair = signing.gen_signing_keypair()
451 
452  # Sign the primary inputs, sender_eph_pk and the ciphertexts
453 
454  result_corrupt2 = None
455  try:
456  joinsplit_sig_charlie = joinsplit_sign(
457  zksnark,
458  pp,
459  new_joinsplit_keypair,
460  charlie_eth_address,
461  [fake_ciphertext0, fake_ciphertext1],
462  proof,
463  public_data)
464  mix_params = MixParameters(
465  proof,
466  public_data,
467  new_joinsplit_keypair.vk,
468  joinsplit_sig_charlie,
469  [fake_ciphertext0, fake_ciphertext1])
470  tx_hash = zeth_client.mix(
471  mix_params,
472  charlie_eth_address,
473  None,
474  EtherValue(BOB_DEPOSIT_ETH))
475  result_corrupt2 = \
476  wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
477  except Exception as e:
478  print(
479  "Charlie's second corruption attempt" +
480  f" successfully rejected! (msg: {e})"
481  )
482  assert(result_corrupt2 is None), \
483  "Charlie managed to corrupt Bob's deposit the second time!"
484 
485  # Case3: Charlie uses the correct mix data, but attempts to send the mix
486  # call from his own address (thereby receiving the output).
487  result_corrupt3 = None
488  try:
489  joinsplit_sig_bob = joinsplit_sign(
490  zksnark,
491  pp,
492  joinsplit_keypair,
493  bob_eth_address,
494  ciphertexts,
495  proof,
496  public_data)
497  mix_params = MixParameters(
498  proof,
499  public_data,
500  joinsplit_keypair.vk,
501  joinsplit_sig_bob,
502  ciphertexts)
503  tx_hash = zeth_client.mix(
504  mix_params,
505  charlie_eth_address,
506  None,
507  EtherValue(BOB_DEPOSIT_ETH),
508  4000000)
509  result_corrupt3 = \
510  wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
511  except Exception as e:
512  print(
513  "Charlie's third corruption attempt" +
514  f" successfully rejected! (msg: {e})"
515  )
516  assert(result_corrupt3 is None), \
517  "Charlie managed to corrupt Bob's deposit the third time!"
518  # ### ATTACK BLOCK
519 
520  # Bob transaction is finally mined
521  joinsplit_sig_bob = joinsplit_sign(
522  zksnark,
523  pp,
524  joinsplit_keypair,
525  bob_eth_address,
526  ciphertexts,
527  proof,
528  public_data)
529  mix_params = MixParameters(
530  proof,
531  public_data,
532  joinsplit_keypair.vk,
533  joinsplit_sig_bob,
534  ciphertexts)
535  tx_hash = zeth_client.mix(
536  mix_params,
537  bob_eth_address,
538  None,
539  EtherValue(BOB_DEPOSIT_ETH))
540  return wait_for_tx_update_mk_tree(zeth_client, mk_tree, tx_hash)
test_commands.scenario.charlie_withdraw
MixResult charlie_withdraw(MixerClient zeth_client, ProverClient prover_client, MerkleTree mk_tree, Tuple[int, ZethNote] input1, str charlie_eth_address, mock.KeyStore keystore)
Definition: scenario.py:169
zeth.cli.zeth_deploy.int
int
Definition: zeth_deploy.py:27
zeth.core.merkle_tree
Definition: merkle_tree.py:1
zeth.core.mixer_client.encrypt_notes
List[bytes] encrypt_notes(List[Tuple[api.ZethNote, EncryptionPublicKey]] notes)
Definition: mixer_client.py:601
zeth.core.mixer_client.MixCallDescription
Definition: mixer_client.py:49
test_commands.scenario.bob_to_charlie
MixResult bob_to_charlie(MixerClient zeth_client, ProverClient prover_client, MerkleTree mk_tree, Tuple[int, ZethNote] input1, str bob_eth_address, mock.KeyStore keystore)
Definition: scenario.py:134
test_commands.scenario.dump_merkle_tree
None dump_merkle_tree(List[bytes] mk_tree)
Definition: scenario.py:37
zeth.core.mixer_client.get_dummy_input_and_address
Tuple[int, api.ZethNote] get_dummy_input_and_address(OwnershipPublicKey a_pk)
Definition: mixer_client.py:241
zeth.core.mixer_client.MixParameters
Definition: mixer_client.py:97
zeth.core.prover_client
Definition: prover_client.py:1
zeth.core.mixer_client
Definition: mixer_client.py:1
test_commands.scenario.bob_deposit
MixResult bob_deposit(MixerClient zeth_client, ProverClient prover_client, MerkleTree mk_tree, str bob_eth_address, mock.KeyStore keystore, Optional[EtherValue] tx_value=None)
Definition: scenario.py:103
test_commands.scenario.charlie_double_withdraw
MixResult charlie_double_withdraw(MixerClient zeth_client, ProverClient prover_client, IZKSnarkProvider zksnark, MerkleTree mk_tree, Tuple[int, ZethNote] input1, str charlie_eth_address, mock.KeyStore keystore)
Definition: scenario.py:200
test_commands.scenario.charlie_corrupt_bob_deposit
MixResult charlie_corrupt_bob_deposit(MixerClient zeth_client, ProverClient prover_client, IZKSnarkProvider zksnark, MerkleTree mk_tree, str bob_eth_address, str charlie_eth_address, mock.KeyStore keystore)
Definition: scenario.py:336
zeth.core.utils
Definition: utils.py:1
zeth.core.mixer_client.joinsplit_sign
int joinsplit_sign(IZKSnarkProvider zksnark, PairingParameters pp, JoinsplitSigKeyPair signing_keypair, str sender_eth_address, List[bytes] ciphertexts, ExtendedProof extproof, List[int] public_data, bool for_dispatch_call=False)
Definition: mixer_client.py:657
zeth.core.mixer_client.compute_h_sig
bytes compute_h_sig(List[bytes] nullifiers, JoinsplitSigVerificationKey sign_vk)
Definition: mixer_client.py:734
zeth.core.contracts
Definition: contracts.py:1
zeth.core.contracts.get_event_logs_from_tx_receipt
Iterator[Any] get_event_logs_from_tx_receipt(Any instance, str event_name, Any tx_receipt)
Definition: contracts.py:226
zeth.core.utils.EtherValue
Definition: utils.py:46
zeth.core.mixer_client.event_args_to_mix_result
MixResult event_args_to_mix_result(Any event_args)
Definition: mixer_client.py:218
zeth.core
Definition: __init__.py:1
zeth.core.zksnark
Definition: zksnark.py:1
zeth.core.zeth_address
Definition: zeth_address.py:1
test_commands.scenario.get_mix_parameters_components
Tuple[ZethNote, ZethNote, ExtendedProof, List[int], JoinsplitSigKeyPair] get_mix_parameters_components(MixerClient zeth_client, ProverClient prover_client, MerkleTree mk_tree, OwnershipKeyPair sender_ownership_keypair, List[Tuple[int, ZethNote]] inputs, List[Tuple[ZethAddressPub, EtherValue]] outputs, EtherValue v_in, EtherValue v_out, Optional[ComputeHSigCB] compute_h_sig_cb=None)
Definition: scenario.py:69
test_commands.scenario.parse_mix_call
MixResult parse_mix_call(Any mixer_instance, Any tx_receipt)
Definition: scenario.py:43
test_commands.scenario.wait_for_tx_update_mk_tree
MixResult wait_for_tx_update_mk_tree(MixerClient zeth_client, MerkleTree mk_tree, str tx_hash)
Definition: scenario.py:55