Esempio n. 1
0
def create_public_key_and_shares_centralized(
        curve_params: CurveParameters,
        threshold_params: ThresholdParameters) -> (PublicKey, List[KeyShare]):
    """
    Creates a public key and n shares by choosing a random secret key and using it for computations.

    :param curve_params: curve parameters to use
    :param threshold_params: parameters t and n for the threshold scheme
    :return: (the public key, n key shares)
    """
    d = number.random_in_range(1, curve_params.order)
    Q = d * curve_params.P
    pk = PublicKey(Q, curve_params)

    # Perform Shamir's secret sharing in Z_q
    polynom = number.PolynomMod.create_random_polynom(d,
                                                      threshold_params.t - 1,
                                                      curve_params.order)
    supporting_points = range(1, threshold_params.n + 1)
    shares = [
        KeyShare(x, polynom.evaluate(x), curve_params)
        for x in supporting_points
    ]

    return pk, shares
Esempio n. 2
0
def _encrypt_key_point(
        key_point: ECC.EccPoint, Q: ECC.EccPoint,
        curve_params: CurveParameters) -> (ECC.EccPoint, ECC.EccPoint):
    k = number.random_in_range(1, curve_params.order)
    C1 = k * curve_params.P
    kQ = k * Q
    C2 = key_point + kQ

    return C1, C2
Esempio n. 3
0
    def test_key_encryption_decryption_without_enough_shares(self):
        r = number.random_in_range(2, self.cp.order)
        testkey_element = r * self.cp.P
        kP, c = central._encrypt_key_point(testkey_element, self.pk.Q, self.cp)
        em = EncryptedMessage(kP, c, b'')
        reconstruct_shares = [self.shares[i] for i in [0, 4]]  # choose 2 of 5 key shares
        partial_decryptions = [participant.compute_partial_decryption(em, share) for share in reconstruct_shares]
        rec_testkey_element = central._combine_shares(partial_decryptions, em, self.cp)

        self.assertNotEqual(testkey_element, rec_testkey_element)
Esempio n. 4
0
def encrypt_message(message: str, public_key: PublicKey) -> EncryptedMessage:
    """
    Encrypt a message using a public key. A hybrid encryption approach is used to include advantages of symmetric
    encryption (fast, independent of message-length, integrity-preserving by using AE-scheme).
    Internally a combination of Salsa20 and Poly1305 from the cryptographic library NaCl is used.

    :param message: the message to be encrypted
    :param public_key: the public key
    :return: the encrypted message
    """
    curve_params = public_key.curve_params
    encoded_message = bytes(message, 'utf-8')

    # Create random subgroup element and use its hash as symmetric key to prevent
    # attacks described in "Why Textbook ElGamal and RSA Encryption Are Insecure"
    # by Boneh et. al.
    r = number.random_in_range(1, curve_params.order)
    key_point = r * curve_params.P
    point_bytes = _key_bytes_from_point(key_point)

    try:
        symmetric_key = nacl.hash.blake2b(
            point_bytes,
            digest_size=nacl.secret.SecretBox.KEY_SIZE,
            encoder=nacl.encoding.RawEncoder)
        # Use derived symmetric key to encrypt the message
        box = nacl.secret.SecretBox(symmetric_key)
        encrypted = box.encrypt(encoded_message)
    except nacl.exceptions.CryptoError as e:
        print('Encryption failed: ' + str(e))
        raise ThresholdCryptoError('Message encryption failed.')

    # Use threshold scheme to encrypt the curve point used as hash input to derive the symmetric key
    C1, C2 = _encrypt_key_point(key_point, public_key.Q, curve_params)

    return EncryptedMessage(C1, C2, encrypted)
Esempio n. 5
0
    def __init__(self, own_id: ParticipantId,
                 all_participant_ids: List[ParticipantId],
                 curve_params: CurveParameters,
                 threshold_params: ThresholdParameters):
        """
        Initialize a participant.

        :param own_id: the id of this participant.
        As this id is used as the final shares x value, it's important that participants use distinct ids.
        :param all_participant_ids: a list of all
        :param curve_params: the curve parameters used
        :param threshold_params: the required threshold parameters
        """
        if len(set(all_participant_ids)) != threshold_params.n:
            raise ThresholdCryptoError(
                "List of distinct participant ids has length {} != {} = n".
                format(len(all_participant_ids), threshold_params.n))

        if own_id not in all_participant_ids:
            raise ThresholdCryptoError(
                "Own id must be contained in all participant ids")

        self.all_participant_ids: List[ParticipantId] = all_participant_ids
        self.id: ParticipantId = own_id
        self.curve_params: CurveParameters = curve_params
        self.threshold_params: ThresholdParameters = threshold_params

        self._x_i: int = number.random_in_range(0, curve_params.order)
        self._h_i: ECC.EccPoint = self._x_i * curve_params.P
        self._polynom: number.PolynomMod = number.PolynomMod.create_random_polynom(
            self._x_i, self.threshold_params.t - 1, curve_params.order)

        # calculate own F_ij values
        self._local_F_ij: List[ECC.EccPoint] = []
        for coeff in self._polynom.coefficients:
            self._local_F_ij.append(coeff * curve_params.P)

        # calculate own s_ij values
        self._local_sij: Dict[ParticipantId, int] = {}
        for p_id in self.all_participant_ids:
            s_ij = self._polynom.evaluate(p_id)
            self._local_sij[p_id] = s_ij

        # random value for commitment of h_i
        rand_int = random.getrandbits(self._COMMITMENT_RANDOM_BITS)
        self._commitment_random: bytes = number.int_to_bytes(rand_int)
        self._commitment: bytes = self._compute_commitment(
            self._commitment_random, self._h_i)

        self._received_closed_commitments: Dict[ParticipantId,
                                                DkgClosedCommitment] = {
                                                    self.id:
                                                    self.closed_commmitment()
                                                }
        self._received_open_commitments: Dict[
            ParticipantId, DkgOpenCommitment] = {
                self.id: self._unchecked_open_commitment()
            }
        self._received_F: Dict[ParticipantId, DkgFijValue] = {
            self.id: self.F_ij_value()
        }
        self._received_sij: Dict[ParticipantId, DkgSijValue] = {
            self.id: self._unchecked_s_ij_value_for_participant(self.id)
        }

        self._s_i: Optional[int] = None
        self.key_share: Optional[KeyShare] = None