コード例 #1
0
class DKGClient:
    def __init__(self, node_id_dkg, node_id_contract, skale, t, n, schain_name,
                 public_keys, node_ids_dkg, node_ids_contract, eth_key_name):
        self.sgx = SgxClient(os.environ['SGX_SERVER_URL'],
                             n=n,
                             t=t,
                             path_to_cert=SGX_CERTIFICATES_FOLDER)
        self.schain_name = schain_name
        self.group_index = skale.web3.sha3(text=self.schain_name)
        self.node_id_contract = node_id_contract
        self.node_id_dkg = node_id_dkg
        self.skale = skale
        self.t = t
        self.n = n
        self.eth_key_name = eth_key_name
        self.incoming_verification_vector = ['0' for _ in range(n)]
        self.incoming_secret_key_contribution = ['0' for _ in range(n)]
        self.public_keys = public_keys
        self.node_ids_dkg = node_ids_dkg
        self.node_ids_contract = node_ids_contract
        self.dkg_contract_functions = self.skale.dkg.contract.functions
        logger.info(
            f'sChain: {self.schain_name}. Node id on chain is {self.node_id_dkg}; '
            f'Node id on contract is {self.node_id_contract}')

    def is_channel_opened(self):
        return self.dkg_contract_functions.isChannelOpened(
            self.group_index).call()

    def generate_polynomial(self, poly_name):
        self.poly_name = poly_name
        return self.sgx.generate_dkg_poly(poly_name)

    def verification_vector(self):
        verification_vector = self.sgx.get_verification_vector(self.poly_name)
        self.incoming_verification_vector[
            self.node_id_dkg] = verification_vector
        verification_vector_hexed = eth_utils.conversions.add_0x_prefix(
            convert_g2_points_to_hex(verification_vector))
        return verification_vector_hexed

    def secret_key_contribution(self):
        self.sent_secret_key_contribution = self.sgx.get_secret_key_contribution(
            self.poly_name, self.public_keys)
        self.incoming_secret_key_contribution[
            self.node_id_dkg] = self.sent_secret_key_contribution[
                self.node_id_dkg * 192:(self.node_id_dkg + 1) * 192]
        return self.sent_secret_key_contribution

    def broadcast(self, poly_name):
        poly_success = self.generate_polynomial(poly_name)
        if not poly_success:
            raise SgxDkgPolynomGenerationError(
                f'sChain: {self.schain_name}. Sgx dkg polynom generation failed'
            )

        is_broadcast_possible_function = self.dkg_contract_functions.isBroadcastPossible
        is_broadcast_possible = is_broadcast_possible_function(
            self.group_index,
            self.node_id_contract).call({'from': self.skale.wallet.address})

        channel_opened = self.is_channel_opened()
        if not is_broadcast_possible or not channel_opened:
            logger.info(
                f'sChain: {self.schain_name}. '
                f'Broadcast is already sent from {self.node_id_dkg} node')
            return

        verification_vector = self.verification_vector()
        secret_key_contribution = self.secret_key_contribution()
        try:
            self.skale.dkg.broadcast(self.group_index,
                                     self.node_id_contract,
                                     verification_vector,
                                     secret_key_contribution,
                                     wait_for=True,
                                     retries=2)
        except TransactionFailedError as e:
            logger.error(f'DKG broadcast failed: sChain {self.schain_name}')
            raise DkgTransactionError(e)
        logger.info(
            f'sChain: {self.schain_name}. Everything is sent from {self.node_id_dkg} node'
        )

    def receive_verification_vector(self, from_node, event):
        input_ = binascii.hexlify(event['args']['verificationVector']).decode()
        self.incoming_verification_vector[from_node] = input_

    def receive_secret_key_contribution(self, from_node, event):
        input_ = binascii.hexlify(
            event['args']['secretKeyContribution']).decode()
        self.incoming_secret_key_contribution[from_node] = input_[
            self.node_id_dkg * 192:(self.node_id_dkg + 1) * 192]

    def verification(self, from_node):
        return self.sgx.verify_secret_share(
            self.incoming_verification_vector[from_node], self.eth_key_name,
            self.incoming_secret_key_contribution[from_node], self.node_id_dkg)

    def send_complaint(self, to_node):
        is_complaint_possible_function = self.dkg_contract_functions.isComplaintPossible
        is_complaint_possible = is_complaint_possible_function(
            self.group_index, self.node_id_contract,
            self.node_ids_dkg[to_node]).call(
                {'from': self.skale.wallet.address})

        if not is_complaint_possible or not self.is_channel_opened():
            logger.info(
                f'sChain: {self.schain_name}. '
                f'{self.node_id_dkg} node could not sent a complaint on {to_node} node'
            )
            return
        self.skale.dkg.complaint(self.group_index,
                                 self.node_id_contract,
                                 self.node_ids_dkg[to_node],
                                 wait_for=True)
        logger.info(
            f'sChain: {self.schain_name}. '
            f'{self.node_id_dkg} node sent a complaint on {to_node} node')

    def response(self, from_node_index):
        is_response_possible_function = self.dkg_contract_functions.isResponsePossible
        is_response_possible = is_response_possible_function(
            self.group_index,
            self.node_id_contract).call({'from': self.skale.wallet.address})

        if not is_response_possible or not self.is_channel_opened():
            logger.info(f'sChain: {self.schain_name}. '
                        f'{from_node_index} node could not sent a response')
            return
        response = self.sgx.complaint_response(
            self.poly_name, self.node_ids_contract[from_node_index])
        share, dh_key = response['share'], response['dh_key']

        share = share.split(':')

        share = convert_g2_point_to_hex(share)
        try:
            self.skale.dkg.response(self.group_index,
                                    self.node_id_contract,
                                    int(dh_key, 16),
                                    eth_utils.conversions.add_0x_prefix(share),
                                    wait_for=True,
                                    retries=2)
        except TransactionFailedError as e:
            logger.error(f'DKG response failed: sChain {self.schain_name}')
            raise DkgTransactionError(e)
        logger.info(
            f'sChain: {self.schain_name}. {from_node_index} node sent a response'
        )

    def receive_from_node(self, from_node, event):
        self.receive_verification_vector(self.node_ids_contract[from_node],
                                         event)
        self.receive_secret_key_contribution(self.node_ids_contract[from_node],
                                             event)
        if not self.verification(self.node_ids_contract[from_node]):
            raise DkgVerificationError(
                f"sChain: {self.schain_name}. "
                f"Fatal error : user {str(self.node_ids_contract[from_node] + 1)} "
                f"hasn't passed verification by user {str(self.node_id_dkg + 1)}"
            )
        logger.info(
            f'sChain: {self.schain_name}. '
            f'All data from {self.node_ids_contract[from_node]} was received and verified'
        )

    def generate_key(self, bls_key_name):
        received_secret_key_contribution = "".join(
            self.incoming_secret_key_contribution[j]
            for j in range(self.sgx.n))
        logger.info(
            f'sChain: {self.schain_name}. '
            f'DKGClient is going to create BLS private key with name {bls_key_name}'
        )
        bls_private_key = self.sgx.create_bls_private_key(
            self.poly_name, bls_key_name, self.eth_key_name,
            received_secret_key_contribution)
        logger.info(
            f'sChain: {self.schain_name}. '
            'DKGClient is going to fetch BLS public key with name {bls_key_name}'
        )
        self.public_key = self.sgx.get_bls_public_key(bls_key_name)
        return bls_private_key

    def alright(self):
        is_alright_possible_function = self.dkg_contract_functions.isAlrightPossible
        is_alright_possible = is_alright_possible_function(
            self.group_index,
            self.node_id_contract).call({'from': self.skale.wallet.address})

        if not is_alright_possible or not self.is_channel_opened():
            logger.info(
                f'sChain: {self.schain_name}. '
                f'{self.node_id_dkg} node has already sent an alright note')
            return
        try:
            self.skale.dkg.alright(self.group_index,
                                   self.node_id_contract,
                                   wait_for=True,
                                   retries=2)
        except TransactionFailedError as e:
            logger.error(f'DKG alright failed: sChain {self.schain_name}')
            raise DkgTransactionError(e)
        logger.info(
            f'sChain: {self.schain_name}. {self.node_id_dkg} node sent an alright note'
        )
コード例 #2
0
def perform_dkg(t, n, with_0x=True, with_complaint=False):
    sgx = SgxClient(os.environ['SERVER'],
                    path_to_cert=os.environ.get('CERT_PATH'),
                    n=n,
                    t=t)

    public_keys = []
    key_name = []

    random_dkg_id = random.randint(0, 10**50)

    for i in range(n):
        generated_key = sgx.generate_key()
        if with_0x:
            public_keys.append(generated_key.public_key)
        else:
            public_keys.append(generated_key.public_key[2:])
        key_name.append(generated_key.name)
        sleep(1)

    for i in range(n):
        poly_name = ("POLY:SCHAIN_ID:"
                     f"{str(0)}"
                     ":NODE_ID:"
                     f"{str(i)}"
                     ":DKG_ID:"
                     f"{str(random_dkg_id)}")
        response = sgx.generate_dkg_poly(poly_name)
        if response == DkgPolyStatus.FAIL:
            raise TypeError("failed generate dkg poly for " + str(i))
        sleep(5)

    verification_vector = []
    for i in range(n):
        poly_name = ("POLY:SCHAIN_ID:"
                     f"{str(0)}"
                     ":NODE_ID:"
                     f"{str(i)}"
                     ":DKG_ID:"
                     f"{str(random_dkg_id)}")
        verification_vector.append(sgx.get_verification_vector(poly_name))
        sleep(5)

    hexed_vv = []

    for vv in verification_vector:
        cur_hexed = ""
        for elem in vv:
            cur_hexed += convert_g2_point_to_hex(elem)
        hexed_vv.append(cur_hexed)

    secret_key_contribution = []
    for i in range(n):
        poly_name = ("POLY:SCHAIN_ID:"
                     f"{str(0)}"
                     ":NODE_ID:"
                     f"{str(i)}"
                     ":DKG_ID:"
                     f"{str(random_dkg_id)}")
        secret_key_contribution.append(
            sgx.get_secret_key_contribution(poly_name, public_keys))
        sleep(5)

    if not with_complaint:
        for i in range(n):
            for j in range(n):
                if not sgx.verify_secret_share(
                        hexed_vv[j], key_name[i],
                        secret_key_contribution[j][192 * i:192 * (i + 1)], i):
                    raise ValueError(f'{i} failed to verify {j}')
                sleep(5)

        public_keys = sgx.calculate_all_bls_public_keys(hexed_vv)

        for i in range(n):
            poly_name = ("POLY:SCHAIN_ID:"
                         f"{str(0)}"
                         ":NODE_ID:"
                         f"{str(i)}"
                         ":DKG_ID:"
                         f"{str(random_dkg_id)}")
            bls_key_name = ("BLS_KEY:SCHAIN_ID:"
                            f"{str(0)}"
                            ":NODE_ID:"
                            f"{str(i)}"
                            ":DKG_ID:"
                            f"{str(random_dkg_id)}")
            sgx.create_bls_private_key(
                poly_name, bls_key_name, key_name[i],
                "".join(secret_key_contribution[j][192 * i:192 * (i + 1)]
                        for j in range(n)))

            public_key = sgx.get_bls_public_key(bls_key_name)

            assert ":".join(public_key) == public_keys[i]

            sleep(5)
    else:
        corrupted_secret_key_contribution = secret_key_contribution[0]
        secret_key_contribution[0] = secret_key_contribution[1]

        for i in range(n):
            for j in range(n):
                if j == 0:
                    assert not sgx.verify_secret_share(
                        hexed_vv[j], key_name[i],
                        secret_key_contribution[j][192 * i:192 * (i + 1)], i)
                else:
                    assert sgx.verify_secret_share(
                        hexed_vv[j], key_name[i],
                        secret_key_contribution[j][192 * i:192 * (i + 1)], i)
                sleep(5)

        poly_name = ("POLY:SCHAIN_ID:"
                     f"{str(0)}"
                     ":NODE_ID:"
                     f"{str(0)}"
                     ":DKG_ID:"
                     f"{str(random_dkg_id)}")
        perform_complaint(sgx, t, poly_name, public_keys[1],
                          corrupted_secret_key_contribution[192:256])