def token_approve(assets: str, mixer_addr: str, asset_addr: str, username: str, password: str): """ Approve the mixer to spend some amount of assets """ approve_value = EtherValue(assets) #eth_addr = load_eth_address(eth_addr) #client_ctx = ctx.obj #web3 = open_web3_from_ctx(client_ctx) #mixer_desc = load_mixer_description_from_ctx(client_ctx) #if not mixer_desc.asset: # raise ClickException("no asset for mixer {mixer_desc.mixer.address}") asset_instance = BAC001(asset_addr) keystore_file = "{}/{}/{}".format(USER_DIR, username, FISCO_ADDRESS_FILE) with open(keystore_file, "r") as dump_f: keytext = json.load(dump_f) privkey = Account.decrypt(keytext, password) asset_instance.client.ecdsa_account = Account.from_key(privkey) keypair = BcosKeyPair() keypair.private_key = asset_instance.client.ecdsa_account.privateKey keypair.public_key = asset_instance.client.ecdsa_account.publickey keypair.address = asset_instance.client.ecdsa_account.address asset_instance.client.keypair = keypair print(f"- {username} approves the transfer of BAC001asset to the Mixer") out, transactionReceipt = asset_instance.approve(mixer_addr, approve_value.wei) print("approve tranaction output", out) outputresult = asset_instance.allowance( asset_instance.client.ecdsa_account.address, mixer_addr) print(f"- The allowance for the Mixer from {username} is: {outputresult}") return outputresult
def load_default_account(self): if client_config.crypto_type == CRYPTO_TYPE_GM: # 加载国密账号 if self.gm_account is not None: return # 不需要重复加载 try: self.gm_account = GM_Account() self.gm_account_file = "{}/{}".format(client_config.account_keyfile_path, client_config.gm_account_keyfile) if os.path.exists(self.gm_account_file) is False: raise BcosException(("gm account keyfile file {} doesn't exist, " "please check client_config.py again " "and make sure this account exist") .format(self.gm_account_file)) self.gm_account.load_from_file( self.gm_account_file, client_config.gm_account_password) self.keypair = self.gm_account.keypair return except Exception as e: raise BcosException("load gm account from {} failed, reason: {}" .format(self.gm_account_file, e)) # 默认的 ecdsa 账号 try: if self.ecdsa_account is not None: return # 不需要重复加载 # check account keyfile self.keystore_file = "{}/{}".format(client_config.account_keyfile_path, client_config.account_keyfile) if os.path.exists(self.keystore_file) is False: raise BcosException(("keystore file {} doesn't exist, " "please check client_config.py again " "and make sure this account exist") .format(self.keystore_file)) with open(self.keystore_file, "r") as dump_f: keytext = json.load(dump_f) privkey = Account.decrypt(keytext, client_config.account_password) self.ecdsa_account = Account.from_key(privkey) keypair = BcosKeyPair() keypair.private_key = self.ecdsa_account.privateKey keypair.public_key = self.ecdsa_account.publickey keypair.address = self.ecdsa_account.address self.keypair = keypair except Exception as e: raise BcosException("load account from {} failed, reason: {}" .format(self.keystore_file, e))
def getBalance(request) -> None: result = {} req = json.loads(request.body) bac_instance = BAC001(req['token_address']) keystore_file = "{}/{}/{}".format(USER_DIR, req['username'], FISCO_ADDRESS_FILE) with open(keystore_file, "r") as dump_f: keytext = json.load(dump_f) privkey = Account.decrypt(keytext, req['password']) bac_instance.client.ecdsa_account = Account.from_key(privkey) keypair = BcosKeyPair() keypair.private_key = bac_instance.client.ecdsa_account.privateKey keypair.public_key = bac_instance.client.ecdsa_account.publickey keypair.address = bac_instance.client.ecdsa_account.address bac_instance.client.keypair = keypair balance = bac_instance.balance(bac_instance.client.ecdsa_account.address) result['status'] = 0 result['balance'] = balance[0] / 1000000000000000000.0 return JsonResponse(result)
def create_zeth_client_and_mixer_desc( prover_server_endpoint: str, mixer_addr: str, username: str, password: str) -> Tuple[MixerClient, MixerDescription]: """ Create a MixerClient and MixerDescription object, for an existing deployment. """ #web3 = open_web3_from_ctx(ctx) #mixer_desc = load_mixer_description_from_ctx(ctx) mixer_instance = Groth16Mixer(mixer_addr) keystore_file = "{}/{}/{}".format(USER_DIR, username, FISCO_ADDRESS_FILE) if exists(keystore_file) is False: raise ClickException(f"invalid output spec: {keystore_file}") with open(keystore_file, "r") as dump_f: keytext = json.load(dump_f) privkey = Account.decrypt(keytext, password) mixer_instance.client.ecdsa_account = Account.from_key(privkey) keypair = BcosKeyPair() keypair.private_key = mixer_instance.client.ecdsa_account.privateKey keypair.public_key = mixer_instance.client.ecdsa_account.publickey keypair.address = mixer_instance.client.ecdsa_account.address mixer_instance.client.keypair = keypair zeth_client = MixerClient.open(prover_server_endpoint, mixer_instance) return (zeth_client)
def sendAsset(request) -> None: result = {} req = json.loads(request.body) asset_instance = BAC001(req['token_address']) keystore_file = "{}/{}/{}".format(USER_DIR, req['username'], FISCO_ADDRESS_FILE) with open(keystore_file, "r") as dump_f: keytext = json.load(dump_f) privkey = Account.decrypt(keytext, req['password']) asset_instance.client.ecdsa_account = Account.from_key(privkey) keypair = BcosKeyPair() keypair.private_key = asset_instance.client.ecdsa_account.privateKey keypair.public_key = asset_instance.client.ecdsa_account.publickey keypair.address = asset_instance.client.ecdsa_account.address asset_instance.client.keypair = keypair print(f"- {req['username']} the transfer of BAC001asset to the Mixer") value = EtherValue(req['value']) out, transactionReceipt = asset_instance.send(req['fiscoAddress'], value.wei, '') print("send tranaction output {}", out) balance = asset_instance.balance(keypair.address) result['status'] = 0 result['balance'] = balance[0] / 1000000000000000000.0 return JsonResponse(result)
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")
class GM_Account(object): keypair = BcosKeyPair() cbc_iv = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' def getdetail(self, sep="\n"): return self.keypair.getdetail(sep) def publickey_to_address(self, publickey): publickeybytes = func.bytes_to_list(bytes(decode_hex(publickey))) hashres = sm3.sm3_hash( publickeybytes ) # sm3_hash 对应sm3_implement.py里的sm3_hash,返回的是hex形态的结果 hash_raw = decode_hex(hashres) # 转为bytes addr_raw = hash_raw[-20:] # 截取20个字节 addr = to_checksum_address(addr_raw) # 转为格式化的地址 return addr def create(self): kp = sm2_helper.sm2_key_pair_gen() self.keypair.private_key = kp[0] self.keypair.public_key = kp[1] self.keypair.address = self.publickey_to_address( self.keypair.public_key) def from_key(self, privkey): self.keypair.public_key = sm2_helper.sm2_privkey_to_pub(privkey) self.keypair.private_key = privkey self.keypair.address = self.publickey_to_address( self.keypair.public_key) def pwd_ljust(self, password): return password.ljust(16, '0') def save_to_file(self, filename, password=None): content = {} key = self.keypair.private_key content["address"] = self.keypair.address content["encrypt"] = False if password is not None: crypt_sm4 = CryptSM4() password = self.pwd_ljust(password) crypt_sm4.set_key(bytes(password, "utf-8"), SM4_ENCRYPT) encrypt_value = crypt_sm4.crypt_cbc( self.cbc_iv, bytes(self.keypair.private_key, "utf-8")) key = str(base64.b64encode(encrypt_value), "utf-8") content["encrypt"] = True content["private_key"] = key content["type"] = "gm" # set mac of the password passwdBytes = bytes(password, "utf-8") content["mac"] = sm3.sm3_hash(passwdBytes) with open(filename, "w") as dump_f: json.dump(content, dump_f, indent=4) dump_f.close() # 从文件加载,格式是json def load_from_file(self, filename, password=None): if password is None: return with open(filename, "r") as dump_f: content = json.load(dump_f) dump_f.close() if content["type"] != "gm": return # get and compare mac expected_mac = content["mac"] password = self.pwd_ljust(password) passwdBytes = bytes(password, "utf-8") mac = sm3.sm3_hash(passwdBytes) if not hmac.compare_digest(mac, expected_mac): raise ValueError("MAC mismatch") key = content["private_key"] crypt_sm4 = CryptSM4() crypt_sm4.set_key(bytes(password, "utf-8"), SM4_DECRYPT) key = base64.b64decode(bytes(key, "utf-8")) key = str(crypt_sm4.crypt_cbc(self.cbc_iv, key), "utf-8") self.from_key(key)