Exemplo n.º 1
0
def main() -> None:
    zksnark_name = zeth.core.utils.parse_zksnark_arg()
    zksnark = zeth.core.zksnark.get_zksnark_provider(zksnark_name)

    web3, eth = mock.open_test_web3()

    # Zeth addresses
    keystore = mock.init_test_keystore()
    # Ethereum addresses
    deployer_eth_address = eth.accounts[0]
    bob_eth_address = eth.accounts[1]
    alice_eth_address = eth.accounts[2]
    charlie_eth_address = eth.accounts[3]

    # ProverClient
    prover_client = ProverClient(mock.TEST_PROVER_SERVER_ENDPOINT)
    prover_config = prover_client.get_configuration()
    pp = prover_config.pairing_parameters
    assert prover_client.get_configuration().zksnark_name == zksnark_name

    # Deploy Zeth contracts
    tree_depth = zeth.core.constants.ZETH_MERKLE_TREE_DEPTH
    zeth_client, _contract_desc = MixerClient.deploy(
        web3,
        prover_client,
        deployer_eth_address,
        None,
        None,
        None)

    # Set up Merkle tree and Wallets. Note that each wallet holds an internal
    # Merkle Tree, unused in this test. Instead, we keep an in-memory version
    # shared by all virtual users. This avoids having to pass all mix results
    # to all wallets, and allows some of the methods in the scenario module,
    # which must update the tree directly.
    tree_hash = get_tree_hash_for_pairing(pp.name)
    mk_tree = zeth.core.merkle_tree.MerkleTree.empty_with_depth(
        tree_depth, tree_hash)
    mixer_instance = zeth_client.mixer_instance

    # Keys and wallets
    def _mk_wallet(name: str, sk: ZethAddressPriv) -> Wallet:
        wallet_dir = join(mock.TEST_NOTE_DIR, name + "-eth")
        if exists(wallet_dir):
            # Note: symlink-attack resistance
            #   https://docs.python.org/3/library/shutil.html#shutil.rmtree.avoids_symlink_attacks
            shutil.rmtree(wallet_dir)
        return Wallet(mixer_instance, name, wallet_dir, sk, tree_hash)

    sk_alice = keystore['Alice'].addr_sk
    sk_bob = keystore['Bob'].addr_sk
    sk_charlie = keystore['Charlie'].addr_sk
    alice_wallet = _mk_wallet('alice', sk_alice)
    bob_wallet = _mk_wallet('bob', sk_bob)
    charlie_wallet = _mk_wallet('charlie', sk_charlie)
    block_num = 1

    # Universal update function
    def _receive_notes(
            out_ev: List[MixOutputEvents]) \
            -> Dict[str, List[ZethNoteDescription]]:
        nonlocal block_num
        notes = {
            'alice': alice_wallet.receive_notes(out_ev, pp),
            'bob': bob_wallet.receive_notes(out_ev, pp),
            'charlie': charlie_wallet.receive_notes(out_ev, pp),
        }
        alice_wallet.update_and_save_state(block_num)
        bob_wallet.update_and_save_state(block_num)
        charlie_wallet.update_and_save_state(block_num)
        block_num = block_num + 1
        return notes

    print("[INFO] 4. Running tests (asset mixed: Ether)...")
    print("- Initial balances: ")
    print_balances(
        web3,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address)

    # Bob deposits ETH, split in 2 notes on the mixer
    result_deposit_bob_to_bob = scenario.bob_deposit(
        zeth_client,
        prover_client,
        mk_tree,
        bob_eth_address,
        keystore)

    print("- Balances after Bob's deposit: ")
    print_balances(
        web3,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address
    )

    # Alice sees a deposit and tries to decrypt the ciphertexts to see if she
    # was the recipient but she wasn't the recipient (Bob was), so she fails to
    # decrypt
    recovered_notes = _receive_notes(result_deposit_bob_to_bob.output_events)
    assert(len(recovered_notes['alice']) == 0), \
        "Alice decrypted a ciphertext that was not encrypted with her key!"

    # Bob does a transfer to Charlie on the mixer

    # Bob decrypts one of the note he previously received (useless here but
    # useful if the payment came from someone else)
    assert(len(recovered_notes['bob']) == 2), \
        f"Bob recovered {len(recovered_notes['bob'])} notes, expected 2"

    # Execution of the transfer
    result_transfer_bob_to_charlie = scenario.bob_to_charlie(
        zeth_client,
        prover_client,
        mk_tree,
        recovered_notes['bob'][0].as_input(),
        bob_eth_address,
        keystore)

    # Bob tries to spend `input_note_bob_to_charlie` twice
    result_double_spending = None
    try:
        result_double_spending = scenario.bob_to_charlie(
            zeth_client,
            prover_client,
            mk_tree,
            recovered_notes['bob'][0].as_input(),
            bob_eth_address,
            keystore)
    except Exception as e:
        print(f"Bob's double spending successfully rejected! (msg: {e})")
    assert(result_double_spending is None), \
        "Bob managed to spend the same note twice!"

    print("- Balances after Bob's transfer to Charlie: ")
    print_balances(
        web3,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address
    )

    # Charlie recovers his notes and attempts to withdraw them.
    recovered_notes = _receive_notes(
        result_transfer_bob_to_charlie.output_events)
    notes_charlie = recovered_notes['charlie']
    assert(len(notes_charlie) == 1), \
        f"Charlie decrypted {len(notes_charlie)}.  Expected 1!"

    input_charlie_withdraw = notes_charlie[0]

    charlie_balance_before_withdrawal = eth.getBalance(charlie_eth_address)
    _ = scenario.charlie_withdraw(
        zeth_client,
        prover_client,
        mk_tree,
        input_charlie_withdraw.as_input(),
        charlie_eth_address,
        keystore)
    charlie_balance_after_withdrawal = eth.getBalance(charlie_eth_address)
    print("Balances after Charlie's withdrawal: ")
    print_balances(
        web3,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address)
    if charlie_balance_after_withdrawal <= charlie_balance_before_withdrawal:
        raise Exception("Charlie's balance did not increase after withdrawal")

    # Charlie tries to double-spend by withdrawing twice the same note
    result_double_spending = None
    try:
        # New commitments are added in the tree at each withdraw so we
        # recompiute the path to have the updated nodes
        result_double_spending = scenario.charlie_double_withdraw(
            zeth_client,
            prover_client,
            zksnark,
            mk_tree,
            input_charlie_withdraw.as_input(),
            charlie_eth_address,
            keystore)
    except Exception as e:
        print(f"Charlie's double spending successfully rejected! (msg: {e})")
    print("Balances after Charlie's double withdrawal attempt: ")
    assert(result_double_spending is None), \
        "Charlie managed to withdraw the same note twice!"
    print_balances(
        web3,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address)

    # Bob deposits once again ETH, split in 2 notes on the mixer
    # But Charlie attempts to corrupt the transaction (malleability attack)
    result_deposit_bob_to_bob = scenario.charlie_corrupt_bob_deposit(
        zeth_client,
        prover_client,
        zksnark,
        mk_tree,
        bob_eth_address,
        charlie_eth_address,
        keystore)

    # Bob decrypts one of the note he previously received (should fail if
    # Charlie's attack succeeded)
    recovered_notes = _receive_notes(
        result_deposit_bob_to_bob.output_events)
    assert(len(recovered_notes['bob']) == 2), \
        f"Bob recovered {len(recovered_notes['bob'])} notes, expected 2"

    print("- Balances after Bob's last deposit: ")
    print_balances(
        web3,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address)

    print(
        "========================================\n" +
        "              TESTS PASSED\n" +
        "========================================\n")
Exemplo n.º 2
0
def main() -> None:

    zksnark = zeth.zksnark.get_zksnark_provider(zeth.utils.parse_zksnark_arg())
    web3, eth = mock.open_test_web3()

    # Ethereum addresses
    deployer_eth_address = eth.accounts[0]
    bob_eth_address = eth.accounts[1]
    alice_eth_address = eth.accounts[2]
    charlie_eth_address = eth.accounts[3]
    # Zeth addresses
    keystore = mock.init_test_keystore()

    # Deploy the token contract
    token_instance = deploy_token(eth, deployer_eth_address, 4000000)

    # Deploy Zeth contracts
    tree_depth = constants.ZETH_MERKLE_TREE_DEPTH
    zeth_client, _contract_desc = MixerClient.deploy(
        web3, mock.TEST_PROVER_SERVER_ENDPOINT, deployer_eth_address,
        token_instance.address, None, zksnark)
    mk_tree = zeth.merkle_tree.MerkleTree.empty_with_depth(tree_depth)
    mixer_instance = zeth_client.mixer_instance

    # Keys and wallets
    def _mk_wallet(name: str, sk: ZethAddressPriv) -> Wallet:
        wallet_dir = join(mock.TEST_NOTE_DIR, name + "-erc")
        if exists(wallet_dir):
            # Note: symlink-attack resistance
            #   https://docs.python.org/3/library/shutil.html#shutil.rmtree.avoids_symlink_attacks
            shutil.rmtree(wallet_dir)
        return Wallet(mixer_instance, name, wallet_dir, sk)

    sk_alice = keystore["Alice"].addr_sk
    sk_bob = keystore["Bob"].addr_sk
    sk_charlie = keystore["Charlie"].addr_sk
    alice_wallet = _mk_wallet('alice', sk_alice)
    bob_wallet = _mk_wallet('bob', sk_bob)
    charlie_wallet = _mk_wallet('charlie', sk_charlie)
    block_num = 1

    # Universal update function
    def _receive_notes(
            out_ev: List[MixOutputEvents]) \
            -> Dict[str, List[ZethNoteDescription]]:
        nonlocal block_num
        notes = {
            'alice': alice_wallet.receive_notes(out_ev),
            'bob': bob_wallet.receive_notes(out_ev),
            'charlie': charlie_wallet.receive_notes(out_ev),
        }
        alice_wallet.update_and_save_state(block_num)
        bob_wallet.update_and_save_state(block_num)
        charlie_wallet.update_and_save_state(block_num)
        block_num = block_num + 1
        return notes

    print("[INFO] 4. Running tests (asset mixed: ERC20 token)...")
    # We assign ETHToken to Bob
    mint_token(token_instance, bob_eth_address, deployer_eth_address,
               2 * scenario.BOB_DEPOSIT_ETH)
    print("- Initial balances: ")
    print_token_balances(token_instance, bob_eth_address, alice_eth_address,
                         charlie_eth_address,
                         zeth_client.mixer_instance.address)

    # Bob tries to deposit ETHToken, split in 2 notes on the mixer (without
    # approving)
    try:
        result_deposit_bob_to_bob = scenario.bob_deposit(
            zeth_client, mk_tree, bob_eth_address, keystore,
            zeth.utils.EtherValue(0))
    except Exception as e:
        allowance_mixer = allowance(token_instance, bob_eth_address,
                                    zeth_client.mixer_instance.address)
        print(f"[ERROR] Bob deposit failed! (msg: {e})")
        print("The allowance for Mixer from Bob is: ", allowance_mixer)

    # Bob approves the transfer
    print("- Bob approves the transfer of ETHToken to the Mixer")
    tx_hash = approve(token_instance, bob_eth_address,
                      zeth_client.mixer_instance.address,
                      scenario.BOB_DEPOSIT_ETH)
    eth.waitForTransactionReceipt(tx_hash)
    allowance_mixer = allowance(token_instance, bob_eth_address,
                                zeth_client.mixer_instance.address)
    print("- The allowance for the Mixer from Bob is:", allowance_mixer)
    # Bob deposits ETHToken, split in 2 notes on the mixer
    result_deposit_bob_to_bob = scenario.bob_deposit(zeth_client, mk_tree,
                                                     bob_eth_address, keystore)

    print("- Balances after Bob's deposit: ")
    print_token_balances(token_instance, bob_eth_address, alice_eth_address,
                         charlie_eth_address,
                         zeth_client.mixer_instance.address)

    # Alice sees a deposit and tries to decrypt the ciphertexts to see if she
    # was the recipient, but Bob was the recipient so Alice fails to decrypt
    received_notes = _receive_notes(result_deposit_bob_to_bob.output_events)
    recovered_notes_alice = received_notes['alice']
    assert(len(recovered_notes_alice) == 0), \
        "Alice decrypted a ciphertext that was not encrypted with her key!"

    # Bob does a transfer of ETHToken to Charlie on the mixer

    # Bob decrypts one of the note he previously received (useless here but
    # useful if the payment came from someone else)
    recovered_notes_bob = received_notes['bob']
    assert(len(recovered_notes_bob) == 2), \
        f"Bob recovered {len(recovered_notes_bob)} notes from deposit, expected 2"
    input_bob_to_charlie = recovered_notes_bob[0].as_input()

    # Execution of the transfer
    result_transfer_bob_to_charlie = scenario.bob_to_charlie(
        zeth_client, mk_tree, input_bob_to_charlie, bob_eth_address, keystore)

    # Bob tries to spend `input_note_bob_to_charlie` twice
    result_double_spending = None
    try:
        result_double_spending = scenario.bob_to_charlie(
            zeth_client, mk_tree, input_bob_to_charlie, bob_eth_address,
            keystore)
    except Exception as e:
        print(f"Bob's double spending successfully rejected! (msg: {e})")
    assert (result_double_spending is None), "Bob spent the same note twice!"

    print("- Balances after Bob's transfer to Charlie: ")
    print_token_balances(token_instance, bob_eth_address, alice_eth_address,
                         charlie_eth_address,
                         zeth_client.mixer_instance.address)

    # Charlie tries to decrypt the notes from Bob's previous transaction.
    received_notes = _receive_notes(
        result_transfer_bob_to_charlie.output_events)
    note_descs_charlie = received_notes['charlie']
    assert(len(note_descs_charlie) == 1), \
        f"Charlie decrypted {len(note_descs_charlie)}.  Expected 1!"

    _ = scenario.charlie_withdraw(zeth_client, mk_tree,
                                  note_descs_charlie[0].as_input(),
                                  charlie_eth_address, keystore)

    print("- Balances after Charlie's withdrawal: ")
    print_token_balances(token_instance, bob_eth_address, alice_eth_address,
                         charlie_eth_address,
                         zeth_client.mixer_instance.address)

    # Charlie tries to carry out a double spend by withdrawing twice the same
    # note
    result_double_spending = None
    try:
        # New commitments are added in the tree at each withdraw so we
        # recompute the path to have the updated nodes
        result_double_spending = scenario.charlie_double_withdraw(
            zeth_client, mk_tree, note_descs_charlie[0].as_input(),
            charlie_eth_address, keystore)
    except Exception as e:
        print(f"Charlie's double spending successfully rejected! (msg: {e})")
    print("Balances after Charlie's double withdrawal attempt: ")
    assert(result_double_spending is None), \
        "Charlie managed to withdraw the same note twice!"
    print_token_balances(token_instance, bob_eth_address, alice_eth_address,
                         charlie_eth_address,
                         zeth_client.mixer_instance.address)

    # Bob deposits once again ETH, split in 2 notes on the mixer
    # But Charlie attempts to corrupt the transaction (malleability attack)

    # Bob approves the transfer
    print("- Bob approves the transfer of ETHToken to the Mixer")
    tx_hash = approve(token_instance, bob_eth_address,
                      zeth_client.mixer_instance.address,
                      scenario.BOB_DEPOSIT_ETH)
    eth.waitForTransactionReceipt(tx_hash)
    allowance_mixer = allowance(token_instance, bob_eth_address,
                                zeth_client.mixer_instance.address)
    print("- The allowance for the Mixer from Bob is:", allowance_mixer)

    result_deposit_bob_to_bob = scenario.charlie_corrupt_bob_deposit(
        zeth_client, mk_tree, bob_eth_address, charlie_eth_address, keystore)

    # Bob decrypts one of the note he previously received (should fail if
    # Charlie's attack succeeded)
    received_notes = _receive_notes(result_deposit_bob_to_bob.output_events)
    recovered_notes_bob = received_notes['bob']
    assert(len(recovered_notes_bob) == 2), \
        f"Bob recovered {len(recovered_notes_bob)} notes from deposit, expected 2"

    print("- Balances after Bob's last deposit: ")
    print_token_balances(token_instance, bob_eth_address, alice_eth_address,
                         charlie_eth_address,
                         zeth_client.mixer_instance.address)

    print("========================================\n" +
          "              TESTS PASSED\n" +
          "========================================\n")
Exemplo n.º 3
0
def main() -> None:
    print("***********************")
    zksnark = zeth.zksnark.get_zksnark_provider("GROTH16")
    #web3, eth = mock.open_test_web3()
    '''
    # Ethereum addresses
    deployer_eth_address = eth.accounts[0]
    bob_eth_address = eth.accounts[1]
    alice_eth_address = eth.accounts[2]
    charlie_eth_address = eth.accounts[3]
    '''

    account_keyfile_path = "python_web3/bin/accounts"  # 保存keystore文件的路径,在此路径下,keystore文件以 [name].keystore命名
    account_keyfile = "pyaccount.keystore"
    keystore_file = "{}/{}".format(account_keyfile_path, account_keyfile)
    with open(keystore_file, "r") as dump_f:
        keytext = json.load(dump_f)
        privkey = Account.decrypt(keytext, "123456")
        deployer_ac = Account.from_key(privkey)

    # Fisco-bcos addresses
    bob_password = "******"
    alice_password = "******"
    charlie_password = "******"
    bob_ac = Account.create(bob_password)
    alice_ac = Account.create(alice_password)
    charlie_ac = Account.create(charlie_password)
    #keypair
    deployer_keypair = BcosKeyPair()
    deployer_keypair.private_key = deployer_ac.privateKey
    deployer_keypair.public_key = deployer_ac.publickey
    deployer_keypair.address = deployer_ac.address
    bob_keypair = BcosKeyPair()
    bob_keypair.private_key = bob_ac.privateKey
    bob_keypair.public_key = bob_ac.publickey
    bob_keypair.address = bob_ac.address
    # alice_keypair = BcosKeyPair()
    # alice_keypair.private_key = alice_ac.privateKey
    # alice_keypair.public_key = alice_ac.publickey
    # alice_keypair.address = alice_ac.address
    charlie_keypair = BcosKeyPair()
    charlie_keypair.private_key = charlie_ac.privateKey
    charlie_keypair.public_key = charlie_ac.publickey
    charlie_keypair.address = charlie_ac.address

    # Zeth addresses
    keystore = mock.init_test_keystore()

    # Deploy Zeth contracts
    tree_depth = constants.ZETH_MERKLE_TREE_DEPTH

    asset_address = deploy_asset("AAAA", "AAA", 18, 100000000)
    token_instance = BAC001(asset_address)
    mixer_address = deploy(asset_address)
    mixer_instance = Groth16Mixer(mixer_address)
    mixer_instance.client.ecdsa_account = deployer_ac
    mixer_instance.client.keypair = deployer_keypair
    print("token address: ", mixer_instance.token())
    zeth_client = MixerClient.open(PROVER_SERVER_ENDPOINT_DEFAULT,
                                   mixer_instance)
    mk_tree = zeth.merkle_tree.MerkleTree.empty_with_depth(tree_depth)

    #mixer_instance = zeth_client.mixer_instance

    # Keys and wallets
    def _mk_wallet(name: str, sk: ZethAddressPriv) -> Wallet:
        wallet_dir = join(mock.TEST_NOTE_DIR, name + "-erc")
        if exists(wallet_dir):
            # Note: symlink-attack resistance
            #   https://docs.python.org/3/library/shutil.html#shutil.rmtree.avoids_symlink_attacks
            shutil.rmtree(wallet_dir)
        return Wallet(mixer_instance, name, wallet_dir, sk)

    sk_alice = keystore["Alice"].addr_sk
    sk_bob = keystore["Bob"].addr_sk
    sk_charlie = keystore["Charlie"].addr_sk
    # alice_wallet = _mk_wallet('alice', sk_alice)
    # bob_wallet = _mk_wallet('bob', sk_bob)
    # charlie_wallet = _mk_wallet('charlie', sk_charlie)
    #block_num = 1

    # Universal update function
    # def _receive_notes(
    #         out_ev: List[MixOutputEvents]) \
    #         -> Dict[str, List[ZethNoteDescription]]:
    #     #nonlocal block_num
    #     notes = {
    #         'alice': alice_wallet.receive_notes(out_ev),
    #         'bob': bob_wallet.receive_notes(out_ev),
    #         'charlie': charlie_wallet.receive_notes(out_ev),
    #     }
    #     alice_wallet.update_and_save_state()
    #     bob_wallet.update_and_save_state()
    #     charlie_wallet.update_and_save_state()
    #     #block_num = block_num + 1
    #     return notes

    print("[INFO] 4. Running tests (asset mixed: ERC20 token)...")
    # We assign ETHToken to Bob

    print("- Initial balances: ")
    print_token_balances(token_instance, bob_ac.address, alice_ac.address,
                         charlie_ac.address, mixer_address)

    # Bob tries to deposit ETHToken, split in 2 notes on the mixer (without
    # approving)
    token_instance.client.ecdsa_account = bob_ac
    token_instance.client.keypair = bob_keypair
    zeth_client.mixer_instance.client.ecdsa_account = bob_ac
    zeth_client.mixer_instance.client.keypair = bob_keypair

    # Bob approves the transfer
    print("- Bob approves the transfer of ETHToken to the Mixer")
    token_instance.client.ecdsa_account = bob_ac
    token_instance.client.keypair = bob_keypair
    (outputresult, receipt) = token_instance.send(bob_ac.address,
                                                  Web3.toWei(10000, 'ether'),
                                                  '')
    print("send *****", receipt['status'])
    (outputresult, receipt) = token_instance.approve(mixer_address,
                                                     scenario.BOB_DEPOSIT_ETH)
    # eth.waitForTransactionReceipt(tx_hash)
    outputresult = token_instance.allowance(deployer_ac.address, mixer_address)
    print("- The allowance for the Mixer from Bob is:", outputresult)
    # # Bob deposits ETHToken, split in 2 notes on the mixer
    # result_deposit_bob_to_bob = scenario.bob_deposit(
    #     zeth_client, mk_tree, bob_ac.address, keystore, zeth.utils.EtherValue(0))
    #
    # print("- Balances after Bob's deposit: ")
    # print_token_balances(
    #     token_instance,
    #     bob_ac.address,
    #     alice_ac.address,
    #     charlie_ac.address,
    #     mixer_address
    # )
    #
    # # Alice sees a deposit and tries to decrypt the ciphertexts to see if she
    # # was the recipient, but Bob was the recipient so Alice fails to decrypt
    # received_notes = _receive_notes(
    #     result_deposit_bob_to_bob.output_events)
    # recovered_notes_alice = received_notes['alice']
    # assert(len(recovered_notes_alice) == 0), \
    #     "Alice decrypted a ciphertext that was not encrypted with her key!"
    #
    # # Bob does a transfer of ETHToken to Charlie on the mixer
    #
    # # Bob decrypts one of the note he previously received (useless here but
    # # useful if the payment came from someone else)
    # recovered_notes_bob = received_notes['bob']
    # assert(len(recovered_notes_bob) == 2), \
    #     f"Bob recovered {len(recovered_notes_bob)} notes from deposit, expected 2"
    # input_bob_to_charlie = recovered_notes_bob[0].as_input()
    '''
    # Execution of the transfer
    result_transfer_bob_to_charlie = scenario.bob_to_charlie(
        zeth_client,
        mk_tree,
        input_bob_to_charlie,
        bob_eth_address,
        keystore)

    # Bob tries to spend `input_note_bob_to_charlie` twice
    result_double_spending = None
    try:
        result_double_spending = scenario.bob_to_charlie(
            zeth_client,
            mk_tree,
            input_bob_to_charlie,
            bob_eth_address,
            keystore)
    except Exception as e:
        print(f"Bob's double spending successfully rejected! (msg: {e})")
    assert(result_double_spending is None), "Bob spent the same note twice!"

    print("- Balances after Bob's transfer to Charlie: ")
    print_token_balances(
        token_instance,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address
    )

    # Charlie tries to decrypt the notes from Bob's previous transaction.
    received_notes = _receive_notes(
        result_transfer_bob_to_charlie.output_events)
    note_descs_charlie = received_notes['charlie']
    assert(len(note_descs_charlie) == 1), \
        f"Charlie decrypted {len(note_descs_charlie)}.  Expected 1!"

    _ = scenario.charlie_withdraw(
        zeth_client,
        mk_tree,
        note_descs_charlie[0].as_input(),
        charlie_eth_address,
        keystore)

    print("- Balances after Charlie's withdrawal: ")
    print_token_balances(
        token_instance,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address
    )

    # Charlie tries to carry out a double spend by withdrawing twice the same
    # note
    result_double_spending = None
    try:
        # New commitments are added in the tree at each withdraw so we
        # recompute the path to have the updated nodes
        result_double_spending = scenario.charlie_double_withdraw(
            zeth_client,
            mk_tree,
            note_descs_charlie[0].as_input(),
            charlie_eth_address,
            keystore)
    except Exception as e:
        print(f"Charlie's double spending successfully rejected! (msg: {e})")
    print("Balances after Charlie's double withdrawal attempt: ")
    assert(result_double_spending is None), \
        "Charlie managed to withdraw the same note twice!"
    print_token_balances(
        token_instance,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address)

    # Bob deposits once again ETH, split in 2 notes on the mixer
    # But Charlie attempts to corrupt the transaction (malleability attack)

    # Bob approves the transfer
    print("- Bob approves the transfer of ETHToken to the Mixer")
    tx_hash = approve(
        token_instance,
        bob_eth_address,
        zeth_client.mixer_instance.address,
        scenario.BOB_DEPOSIT_ETH)
    eth.waitForTransactionReceipt(tx_hash)
    allowance_mixer = allowance(
        token_instance,
        bob_eth_address,
        zeth_client.mixer_instance.address)
    print("- The allowance for the Mixer from Bob is:", allowance_mixer)

    result_deposit_bob_to_bob = scenario.charlie_corrupt_bob_deposit(
        zeth_client,
        mk_tree,
        bob_eth_address,
        charlie_eth_address,
        keystore)

    # Bob decrypts one of the note he previously received (should fail if
    # Charlie's attack succeeded)
    received_notes = _receive_notes(
        result_deposit_bob_to_bob.output_events)
    recovered_notes_bob = received_notes['bob']
    assert(len(recovered_notes_bob) == 2), \
        f"Bob recovered {len(recovered_notes_bob)} notes from deposit, expected 2"

    print("- Balances after Bob's last deposit: ")
    print_token_balances(
        token_instance,
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        zeth_client.mixer_instance.address)
    '''
    print("========================================\n" +
          "              TESTS PASSED\n" +
          "========================================\n")
Exemplo n.º 4
0
def main() -> None:
    zksnark = zeth.zksnark.get_zksnark_provider(zeth.utils.parse_zksnark_arg())

    # Zeth addresses
    keystore = mock.init_test_keystore()
    # Depth of the merkle tree (need to match the one used in the cpp prover)
    mk_tree_depth = constants.ZETH_MERKLE_TREE_DEPTH
    # Ethereum addresses
    deployer_eth_address = eth.accounts[0]
    bob_eth_address = eth.accounts[1]
    alice_eth_address = eth.accounts[2]
    charlie_eth_address = eth.accounts[3]

    prover_client = ProverClient(TEST_GRPC_ENDPOINT)

    coinstore_dir = os.environ['ZETH_COINSTORE']

    # Keys and wallets
    k_sk_alice = keystore["Alice"].addr_sk.k_sk
    k_sk_bob = keystore["Bob"].addr_sk.k_sk
    k_sk_charlie = keystore["Charlie"].addr_sk.k_sk

    alice_wallet = Wallet("alice", coinstore_dir, k_sk_alice)
    bob_wallet = Wallet("bob", coinstore_dir, k_sk_bob)
    charlie_wallet = Wallet("charlie", coinstore_dir, k_sk_charlie)

    print("[INFO] 1. Fetching the verification key from the proving server")
    vk = prover_client.get_verification_key()

    print("[INFO] 2. Received VK, writing the key...")
    zeth.joinsplit.write_verification_key(vk, zksnark)

    print("[INFO] 3. VK written, deploying the smart contracts...")
    (proof_verifier_interface, otsig_verifier_interface, mixer_interface) = \
        zeth.contracts.compile_contracts(zksnark)
    hasher_interface, _ = zeth.contracts.compile_util_contracts()
    (mixer_instance, initial_root) = zeth.contracts.deploy_contracts(
        mk_tree_depth,
        proof_verifier_interface,
        otsig_verifier_interface,
        mixer_interface,
        hasher_interface,
        deployer_eth_address,
        4000000,
        # We mix Ether in this test, so we set the addr of the ERC20 contract
        # to be 0x0
        "0x0000000000000000000000000000000000000000",
        zksnark
    )

    zeth_client = zeth.joinsplit.ZethClient(
        prover_client, mixer_instance, zksnark)

    print("[INFO] 4. Running tests (asset mixed: Ether)...")
    print("- Initial balances: ")
    print_balances(
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        mixer_instance.address)

    # Bob deposits ETH, split in 2 notes on the mixer
    result_deposit_bob_to_bob = scenario.bob_deposit(
        zeth_client,
        initial_root,
        bob_eth_address,
        keystore,
        mk_tree_depth
    )
    new_merkle_root_bob_to_bob = result_deposit_bob_to_bob.new_merkle_root

    print("- Balances after Bob's deposit: ")
    print_balances(
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        mixer_instance.address
    )

    # Alice sees a deposit and tries to decrypt the ciphertexts to see if she
    # was the recipient but she wasn't the recipient (Bob was), so she fails to
    # decrypt
    recovered_notes_alice = alice_wallet.receive_notes(
        result_deposit_bob_to_bob.encrypted_notes,
        result_deposit_bob_to_bob.sender_k_pk)
    assert(len(recovered_notes_alice) == 0), \
        "Alice decrypted a ciphertext that was not encrypted with her key!"

    # Bob does a transfer to Charlie on the mixer

    # Bob decrypts one of the note he previously received (useless here but
    # useful if the payment came from someone else)
    recovered_notes_bob = bob_wallet.receive_notes(
        result_deposit_bob_to_bob.encrypted_notes,
        result_deposit_bob_to_bob.sender_k_pk)
    assert(len(recovered_notes_bob) == 2), \
        f"Bob recovered {len(recovered_notes_bob)} notes from deposit, expected 2"
    bob_to_charlie = recovered_notes_bob[0]

    # Execution of the transfer
    result_transfer_bob_to_charlie = scenario.bob_to_charlie(
        zeth_client,
        new_merkle_root_bob_to_bob,
        bob_to_charlie,
        bob_eth_address,
        keystore,
        mk_tree_depth)

    new_merkle_root_bob_to_charlie = \
        result_transfer_bob_to_charlie.new_merkle_root

    # Bob tries to spend `input_note_bob_to_charlie` twice
    result_double_spending = None
    try:
        result_double_spending = scenario.bob_to_charlie(
            zeth_client,
            new_merkle_root_bob_to_bob,
            bob_to_charlie,
            bob_eth_address,
            keystore,
            mk_tree_depth)
    except Exception as e:
        print(f"Bob's double spending successfully rejected! (msg: {e})")
    assert(result_double_spending is None), \
        "Bob managed to spend the same note twice!"

    print("- Balances after Bob's transfer to Charlie: ")
    print_balances(
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        mixer_instance.address
    )

    # Charlie recovers his notes and attempts to withdraw them.
    notes_charlie = charlie_wallet.receive_notes(
        result_transfer_bob_to_charlie.encrypted_notes,
        result_transfer_bob_to_charlie.sender_k_pk)
    assert(len(notes_charlie) == 1), \
        f"Charlie decrypted {len(notes_charlie)}.  Expected 1!"

    input_charlie_withdraw = notes_charlie[0]
    assert input_charlie_withdraw[0] == \
        result_transfer_bob_to_charlie.encrypted_notes[1][0]

    result_charlie_withdrawal = scenario.charlie_withdraw(
        zeth_client,
        new_merkle_root_bob_to_charlie,
        input_charlie_withdraw,
        charlie_eth_address,
        keystore,
        mk_tree_depth)
    new_merkle_root_charlie_withdrawal = result_charlie_withdrawal.new_merkle_root
    print("Balances after Charlie's withdrawal: ")
    print_balances(
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        mixer_instance.address
    )

    # Charlie tries to double-spend by withdrawing twice the same note
    result_double_spending = None
    try:
        # New commitments are added in the tree at each withdraw so we
        # recompiute the path to have the updated nodes
        result_double_spending = scenario.charlie_double_withdraw(
            zeth_client,
            new_merkle_root_charlie_withdrawal,
            input_charlie_withdraw,
            charlie_eth_address,
            keystore,
            mk_tree_depth)
    except Exception as e:
        print(f"Charlie's double spending successfully rejected! (msg: {e})")
    print("Balances after Charlie's double withdrawal attempt: ")
    assert(result_double_spending is None), \
        "Charlie managed to withdraw the same note twice!"
    print_balances(
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        mixer_instance.address
    )

    # Bob deposits once again ETH, split in 2 notes on the mixer
    # But Charlie attempts to corrupt the transaction (malleability attack)
    result_deposit_bob_to_bob = scenario.charlie_corrupt_bob_deposit(
        zeth_client,
        new_merkle_root_charlie_withdrawal,
        bob_eth_address,
        charlie_eth_address,
        keystore,
        mk_tree_depth)

    # Bob decrypts one of the note he previously received (should fail if
    # Charlie's attack succeeded)
    recovered_notes_bob = bob_wallet.receive_notes(
        result_deposit_bob_to_bob.encrypted_notes,
        result_deposit_bob_to_bob.sender_k_pk)
    assert(len(recovered_notes_bob) == 2), \
        f"Bob recovered {len(recovered_notes_bob)} notes from deposit, expected 2"

    print("- Balances after Bob's last deposit: ")
    print_balances(
        bob_eth_address,
        alice_eth_address,
        charlie_eth_address,
        mixer_instance.address
    )