Example #1
0
    def dispute(self, issuer_id, check_contract_phase=True):
        """ submits a dispute for the given (malicious) share issuer to the smart contract
        """
        if check_contract_phase:
            assert self.contract.sharing_confirmed()

        issuer = self.nodes[issuer_id - 1]

        # distingush between two cases
        # a) the computed public key or (at least one) public coefficient is not a valid elliptic curve point
        for i, c in enumerate(issuer.public_coefficients):
            if not crypto.is_on_curve(c):
                self.contract.dispute_public_coefficient(
                    issuer.account,
                    issuer.encrypted_shares,
                    utils.flatten(issuer.public_coefficients),
                    i,
                    transact={'from': self.account},
                )
                return

        # b) the (encrypted) share is invalid
        return self.contract.dispute_share(
            issuer.account,
            issuer.encrypted_shares,
            utils.flatten(issuer.public_coefficients),
            vss.shared_key(self.sk, issuer.pk),
            vss.shared_key_proof(self.sk, issuer.pk),
            transact={'from': self.account},
        )
Example #2
0
    def load_shares(self, issuer_id: int, encrypted_shares: List[int],
                    public_coefficients: List[PointG1]) -> None:
        """ 1. stores the given information
            2. extracts and decrypts the share for the node itself
            3. verifies this share and raises an ValueError if it is not valid
        """
        assert len(encrypted_shares
                   ) == self.n - 1, "invalid number of encrypted shares"
        assert len(public_coefficients
                   ) == self.t - 1, "invalid number of public_coefficients"

        issuer = self.nodes[issuer_id - 1]
        issuer.encrypted_shares = encrypted_shares
        issuer.public_coefficients = public_coefficients

        share_idx = self.id - 1 if self.id < issuer_id else self.id - 2
        encrypted_share = encrypted_shares[share_idx]
        issuer.share = vss.decrypt_share(encrypted_share, self.id,
                                         vss.shared_key(self.sk, issuer.pk))

        # verify that coefficients are valid points
        issuer.coefficients_ok = all(
            crypto.is_on_curve(c) for c in issuer.public_coefficients)
        issuer.share_ok = issuer.coefficients_ok and vss.verify(
            self.id,
            issuer.share,
            public_coefficients=[issuer.pk] + issuer.public_coefficients)

        if not issuer.share_ok:
            raise ValueError("Share verification failed.")
def manipulate_share(node, sid):
    node.shares[sid - 1] += 1
    node.encrypted_shares = []
    for n, share in zip(node.nodes, node.shares):
        if n != node:
            shared_key = vss.shared_key(node.sk, n.pk)
            encrypted_share = vss.encrypt_share(share, n.id, shared_key)
            node.encrypted_shares.append(encrypted_share)
def test_verify_decryption_key():
    sk1, sk2 = random_scalar(), random_scalar()
    pk1, pk2 = multiply(G1, sk1), multiply(G1, sk2)

    shared_key = vss.shared_key(sk1, pk2)
    chal, resp = vss.shared_key_proof(sk1, pk2)

    assert vss.dleq_verify(G1, pk1, pk2, shared_key, chal, resp)
    assert contract.verify_decryption_key(shared_key, [chal, resp], pk1, pk2)
Example #5
0
def test_load_invalid_shares():
    nodes = setup_and_register()
    bad_node = nodes[0]
    bad_node.encrypted_shares = [
        vss.encrypt_share(share + 1, receiver.id,
                          vss.shared_key(bad_node.sk, receiver.pk))
        for share, receiver in zip(bad_node.shares[1:], nodes[1:])
    ]
    for receiver in nodes[1:]:
        with pytest.raises(ValueError):
            receiver.load_shares(bad_node.id, bad_node.encrypted_shares,
                                 bad_node.public_coefficients)
Example #6
0
    def init_secret_sharing(self,
                            nodes: List['Node'],
                            id: int = None,
                            threshold: int = None):
        """ 1. assign the id obtained from the registration to the node
            2. derive/pick secret coefficients to initialize the node's secret polynomial
            3. compute shares of all nodes
            4. compute public coefficients
            5. store the node's share for itself
            Args:
                id: the id the node got assigned during the registration
                nodes: list of all registered nodes
                threshold: number of collaborating nodes required to recover; set to floor(N/2) + 1 if not provided
        """
        assert self.sk is not None, "call to keygen() is required before starting secret sharing"

        if id is not None:
            self.id = id
        assert self.id is not None, 'assignment of an id is required prior to the key sharing operation'

        self.n = len(nodes)
        self.t = threshold or (self.n // 2 + 1)

        self.nodes = [self if node.idx == self.idx else node for node in nodes]
        assert [node.id for node in nodes] == list(range(
            1, self.n + 1)), 'use of the ids [1, 2, ..., n] is required'

        shares, public_coefficients = vss.share(self.sk, self.n, self.t)

        self.share = shares[self.idx]
        self.share_ok = True
        self.coefficients_ok = True
        self.shares = shares

        # encrypt all shares for OTHER nodes used individual shared keys
        self.encrypted_shares = []
        for node, share in zip(self.nodes, shares):
            if node != self:
                shared_key = vss.shared_key(self.sk, node.pk)
                encrypted_share = vss.encrypt_share(share, node.id, shared_key)
                self.encrypted_shares.append(encrypted_share)

        # remove C0 to form the list of public_coefficients as commitments to the shares,
        # C0 is already given by the node's public keys
        self.public_coefficients = public_coefficients[1:]
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)
Example #8
0
def share_key():
    logging.info('KEY SHARING PHASE STARTED')
    logging.info()
    node.init_secret_sharing()

    logging.info(f'loading registration data...')
    logging.info(f'    assigned id for this node:            {node.id}')
    logging.info(f'    number of register nodes (n):         {node.n}')
    logging.info(f'    signing / key recovery threshold (t): {node.t}')
    logging.info()

    logging.info('generating key shares...')
    for n, s in zip(node.nodes, node.shares):
        logging.info(f'    node {n.id}: {s}')
    logging.info()

    if args.send_invalid_shares is not None:
        sids = args.send_invalid_shares
        logging.info()
        for sid in sids:
            logging.info(f'MANIPULATING SHARE FOR NODE WITH ID {sid}')
            node.shares[sid - 1] += 1
        logging.info()
        node.encrypted_shares = []
        for n, share in zip(node.nodes, node.shares):
            if n != node:
                shared_key = vss.shared_key(node.sk, n.pk)
                encrypted_share = vss.encrypt_share(share, n.id, shared_key)
                node.encrypted_shares.append(encrypted_share)

    logging.info('encrypting key shares...')
    j = 0
    for n in node.nodes:
        if n.id == node.id:
            logging.info(f'    node {n.id}: <no encrypted share for oneself>')
        else:
            logging.info(f'    node {n.id}: {node.shares[j]}')
            j += 1
    logging.info()

    logging.info('sending key sharing transaction...')
    tx = node.share_key()
    log_tx(tx, 'key sharing transaction confirmed')