def test_sharing_late(): contract, nodes = setup_multiple(register=True) utils.run([node.share_key for node in nodes[1:]]) utils.mine_blocks_until(lambda: not contract.in_sharing_phase()) with pytest.raises(ValueError, match='.*key sharing failed.*'): nodes[0].share_key()
def test_registration_prohibt_late_submission(): node, contract = setup_single() utils.mine_blocks_until(lambda: not contract.in_registration_phase()) with pytest.raises(AssertionError): node.register() with pytest.raises(ValueError, match='.*registration failed.*'): node.register(check_contract_phase=False) events = utils.get_events(contract, EVENT_REGISTRATION) assert len(events) == 0
def test_init_secret_sharing(): contract, nodes = setup_multiple() utils.run([node.register for node in nodes]) utils.mine_blocks_until(contract.registrations_confirmed) utils.run([node.init_secret_sharing for node in nodes]) for node in nodes: assert len(node.nodes) == len(nodes)
def test_verification_of_valid_shares(test_dispute=True): contract, nodes = setup_multiple(register=True) utils.run([node.share_key for node in nodes]) utils.mine_blocks_until(contract.sharing_confirmed) # as everything is valid, no node should raise an exception during loading of the shares for node in nodes: node.load_shares() if test_dispute: with pytest.raises(ValueError, match='.*dispute failed.*share was valid.*'): nodes[0].dispute(issuer_id=nodes[-1].id)
def test_verification_invalid_public_coefficients(test_dispute=True): contract, nodes = setup_multiple(3, register=True) issuer, verifier = nodes[0], nodes[2] # invalidate first public coefficient C1x, C1y = issuer.public_coefficients[0] issuer.public_coefficients[0] = (C1x + 1, C1y) utils.run([node.share_key for node in nodes]) utils.mine_blocks_until(contract.sharing_confirmed) with pytest.raises(ValueError): verifier.load_shares() # dispute should succeed and not raise any error if test_dispute: verifier.dispute(issuer_id=nodes[0].id)
def test_upload_group_key(): contract, nodes = setup_multiple(3, register=True) utils.run([node.share_key for node in nodes]) utils.mine_blocks_until(contract.sharing_confirmed) utils.run([node.load_shares() for node in nodes]) utils.mine_blocks_until(contract.dispute_confirmed) nodes[0].derive_group_keys() assert crypto.check_pairing( nodes[0].master_pk, crypto.G2, crypto.G1, nodes[0].master_bls_pk, ) nodes[0].upload_group_key()
def test_verification_of_invalid_shares(test_dispute=True): contract, nodes = setup_multiple(3, register=True) issuer, verifier = nodes[0], nodes[2] share = issuer.shares[verifier.id - 1] invalid_share = share + 1 invalid_encrypted_share = vss.encrypt_share( invalid_share, verifier.id, vss.shared_key(issuer.sk, verifier.pk)) issuer.encrypted_shares[-1] = invalid_encrypted_share utils.run([node.share_key for node in nodes]) utils.mine_blocks_until(contract.sharing_confirmed) with pytest.raises(ValueError): verifier.load_shares() # dispute should succeed and not raise any error if test_dispute: verifier.dispute(issuer_id=issuer.id)
def setup_multiple(num_nodes=3, register=False): assert num_nodes <= len(w3.eth.accounts), \ "Each node needs a seperate account, update e.g. Ganache settings for more accounts" contract = utils.deploy_contract('DKG') nodes = [EthNode(w3.eth.accounts[i]) for i in range(num_nodes)] for node in nodes: c = utils.get_contract('DKG', contract.address) node.keygen() node.connect(c) if register: utils.run([node.register for node in nodes]) utils.mine_blocks_until(contract.registrations_confirmed) utils.run([node.init_secret_sharing for node in nodes]) # here we actually ensure that we return the nodes ordered by id, for easier tests nodes.sort(key=lambda node: node.id) return contract, nodes
def test_sharing_non_registered(): contractA, nodes = setup_multiple(6) contractB = utils.deploy_contract('DKG') nodesA = nodes[:3] nodesB = nodes[3:] for b in nodesB: b.contract = contractB utils.run([node.register for node in nodesA]) utils.run([node.register for node in nodesB]) utils.mine_blocks_until(contractA.registrations_confirmed) utils.mine_blocks_until(contractB.registrations_confirmed) utils.run([node.init_secret_sharing for node in nodesA]) utils.run([node.init_secret_sharing for node in nodesB]) bad_node = nodesB[0] bad_node.contract = contractA with pytest.raises(ValueError, match='.*key sharing failed.*'): # bad_node is not registered for contract A, call to contract should therefore fail bad_node.share_key()
def run(num_nodes): contract = utils.deploy_contract('DKG') nodes = [EthNode(w3.eth.accounts[i]) for i in range(num_nodes)] tx_register = [] tx_share_key = [] tx_dispute = [] tx_upload = None for i, node in enumerate(nodes): print(f'setting up node {i + 1}... ', end="", flush=True) c = utils.get_contract('DKG', contract.address) node.keygen() node.connect(c) print("done") print() for i, node in enumerate(nodes): print(f'registering node {i + 1}... ', end="", flush=True) tx = node.register() tx_register.append(tx) print("done") print() print(f'waiting for begin of key sharing phase... ', end='', flush=True) utils.mine_blocks_until(contract.registrations_confirmed) print('done\n') for i, node in enumerate(nodes): print(f'init secret sharing for node {i + 1}... ', end="", flush=True) node.init_secret_sharing() print("done") print() # invalid the share from last to first node # to actually also test the dispute case manipulate_share(nodes[-1], 1) for node in nodes: print(f'distribute key shares for node {node.id}... ', end="", flush=True) tx = node.share_key() tx_share_key.append(tx) print("done") print() print(f'waiting for begin of dispute phase... ', end='', flush=True) utils.mine_blocks_until(contract.sharing_confirmed) print('done\n') # for node in nodes: for node in nodes[:1]: print(f'loading and verififying shares for node {node.id}... ', end='', flush=True) try: node.load_shares() except ValueError: print("done (invalid share detected)") else: print("done") print() # for node in nodes: for node in nodes[:1]: dispute_ids = [n.id for n in node.nodes if hasattr(n, 'share') and not n.share_ok] for id in dispute_ids: print(f'submitting dispute from node {node.id} against node {id}... ', end="", flush=False) try: tx = node.dispute(id) tx_dispute.append(tx) except ValueError: print(f'done (dispute no required, node {id} already flagged as malicous)') else: print("done") print() print(f'waiting for begin of finalization phase... ', end='', flush=True) utils.mine_blocks_until(contract.dispute_confirmed) print('done\n') print(f'loading dispute and state information... ', end='', flush=True) nodes[0].verify_nodes() print("done\n") for node in nodes[0].nodes: t = 'OK' if node in nodes[0].group else 'FAILED' print(f'node {node.id}: status={t}') print() print(f'deriving master key... ', end='', flush=True) nodes[0].derive_group_keys() print("done") print(f'uploading master key... ', end='', flush=True) tx_upload = nodes[0].upload_group_key() print("done") print() print() print(f'GAS USAGE STATS FOR {num_nodes} NODES') print() print(' | min | max | avg') print('-----------------------------------------------') for txs, name in zip([tx_register, tx_share_key, tx_dispute], ['registration', 'key sharing', 'dispute']): gas_min = min(tx['gasUsed'] for tx in txs) gas_max = max(tx['gasUsed'] for tx in txs) gas_avg = math.ceil(sum(tx['gasUsed'] for tx in txs) / len(txs)) print(f'{name:<17} | {gas_min:7} | {gas_max:7} | {gas_avg:7}') print('-----------------------------------------------') g = tx_upload['gasUsed'] # noqa print(f'master key upload | {g:7} | {g:7} | {g:7} ') print() print() print() print("=" * 80) print("=" * 80) print("=" * 80) print() print() print()