Exemple #1
0
    def _get_dealer_msg(self, values, n):
        # Sample a random degree-(t,t) bivariate polynomial φ(·,·)
        # such that each φ(0,k) = sk and φ(i,k) is Pi’s share of sk
        while len(values) % (self.t + 1) != 0:
            values.append(0)
        secret_count = len(values)
        # batch_count = secret_count/(self.t + 1)
        phi = [None] * secret_count
        commitments = [None] * secret_count
        aux_poly = [None] * secret_count
        # for k ∈ [t+1]
        #   Ck, auxk <- PolyCommit(SP,φ(·,k))
        for k in range(secret_count):
            phi[k] = self.poly.random(self.t, values[k])
            commitments[k], aux_poly[k] = self.poly_commit.commit(phi[k])

        ephemeral_secret_key = self.field.random()
        ephemeral_public_key = pow(self.g, ephemeral_secret_key)
        # for each party Pi and each k ∈ [t+1]
        #   1. w[i][k] <- CreateWitnesss(Ck,auxk,i)
        #   2. z[i][k] <- EncPKi(φ(i,k), w[i][k])
        dispersal_msg_list = [None] * n
        for i in range(n):
            shared_key = pow(self.public_keys[i], ephemeral_secret_key)
            z = [None] * secret_count
            for k in range(secret_count):
                witness = self.poly_commit.create_witness(
                    phi[k], aux_poly[k], i + 1)
                z[k] = (int(phi[k](i + 1)), int(aux_poly[k](i + 1)), witness)
            zz = SymmetricCrypto.encrypt(str(shared_key).encode(), z)
            dispersal_msg_list[i] = zz

        return dumps((commitments, ephemeral_public_key)), dispersal_msg_list
Exemple #2
0
        def _get_dealer_msg(self, values, n):
            fault_n = randint(1, n - 1)
            secret_size = len(values)
            phi = [None] * secret_size
            commitments = [None] * secret_size
            aux_poly = [None] * secret_size
            for k in range(secret_size):
                phi[k] = self.poly.random(self.t, values[k])
                commitments[k], aux_poly[k] = self.poly_commit.commit(phi[k])

            ephemeral_secret_key = self.field.random()
            ephemeral_public_key = pow(self.g, ephemeral_secret_key)
            dispersal_msg_list = [None] * n
            for i in range(n):
                shared_key = pow(self.public_keys[i], ephemeral_secret_key)
                z = [None] * secret_size
                for k in range(secret_size):
                    witness = self.poly_commit.create_witness(
                        phi[k], aux_poly[k], i + 1)
                    if i == fault_n:
                        z[k] = (ZR.random(), ZR.random(), witness)
                    else:
                        z[k] = (phi[k](i + 1), aux_poly[k](i + 1), witness)
                zz = SymmetricCrypto.encrypt(str(shared_key).encode(), z)
                dispersal_msg_list[i] = zz
            return dumps(
                (commitments, ephemeral_public_key)), dispersal_msg_list
Exemple #3
0
    def _get_dealer_msg(self, value):
        if type(value) in (list, tuple):
            valuelist = value
        else:
            valuelist = [value]
        philist, commitlist, auxlist = [], [], []
        for val in valuelist:
            phi = self.poly.random(self.t, val)
            philist.append(phi)
            # Todo: precompute commit stuff
            commitment, aux_poly = self.poly_commit.commit(phi)
            commitlist.append(commitment)
            auxlist.append(aux_poly)
        ephemeral_secret_key = self.field.random()
        ephemeral_public_key = pow(self.g, ephemeral_secret_key)
        z = [None] * self.n
        for i in range(self.n):
            shared_key = pow(self.public_keys[i], ephemeral_secret_key)
            shares, witnesses = [], []
            for j in range(len(philist)):
                shares.append(philist[j](i + 1))
                witnesses.append(
                    self.poly_commit.create_witness(auxlist[j], i + 1))
            z[i] = SymmetricCrypto.encrypt(
                str(shared_key).encode(), (shares, witnesses))

        return dumps((commitlist, ephemeral_public_key, z))
Exemple #4
0
        def _get_dealer_msg(self, value):
            if type(value) in (list, tuple):
                valuelist = value
            else:
                valuelist = [value]
            philist, commitlist, auxlist = [], [], []
            fault_i = randint(0, self.n - 1)
            for val in valuelist:
                phi = self.poly.random(self.t, val)
                philist.append(phi)
                commitment, aux_poly = self.poly_commit.commit(phi)
                commitlist.append(commitment)
                auxlist.append(aux_poly)
            ephemeral_secret_key = self.field.random()
            ephemeral_public_key = pow(self.g, ephemeral_secret_key)
            z = [None] * self.n
            for i in range(self.n):
                shared_key = pow(self.public_keys[i], ephemeral_secret_key)
                shares, witnesses = [], []
                for phi in philist:
                    shares.append(phi(i + 1))
                for aux in auxlist:
                    witnesses.append(
                        self.poly_commit.create_witness(aux, i + 1))
                if i == fault_i:
                    shares[20] = ZR.random()
                z[i] = SymmetricCrypto.encrypt(
                    str(shared_key).encode(), (shares, witnesses))

            return dumps((commitlist, ephemeral_public_key, z))
Exemple #5
0
        def _get_dealer_msg(self, values, n):
            # Sample B random degree-(t) polynomials of form φ(·)
            # such that each φ_i(0) = si and φ_i(j) is Pj’s share of si
            # The same as B (batch_size)
            fault_n = randint(1, n - 1)
            fault_k = randint(1, len(values) - 1)
            secret_count = len(values)
            phi = [None] * secret_count
            commitments = [None] * secret_count
            # BatchPolyCommit
            #   Cs  <- BatchPolyCommit(SP,φ(·,k))
            # TODO: Whether we should keep track of that or not
            r = ZR.random()
            for k in range(secret_count):
                phi[k] = self.poly.random(self.t, values[k])
                commitments[k] = self.poly_commit.commit(phi[k], r)

            ephemeral_secret_key = self.field.random()
            ephemeral_public_key = pow(self.g, ephemeral_secret_key)
            dispersal_msg_list = [None] * n
            witnesses = self.poly_commit.double_batch_create_witness(phi, r)
            for i in range(n):
                shared_key = pow(self.public_keys[i], ephemeral_secret_key)
                phis_i = [phi[k](i + 1) for k in range(secret_count)]
                if i == fault_n:
                    phis_i[fault_k] = ZR.random()
                z = (phis_i, witnesses[i])
                zz = SymmetricCrypto.encrypt(str(shared_key).encode(), z)
                dispersal_msg_list[i] = zz
                dispersal_msg_list[i] = zz

            return dumps(
                (commitments, ephemeral_public_key)), dispersal_msg_list
Exemple #6
0
        def _get_dealer_msg(self, values, n):
            # Notice we currently required the number of values shared to be divisible by t+1.
            secret_count = len(values)
            redundant_poly_count = secret_count // (self.t +
                                                    1) * (n - (self.t + 1))
            r = ZR.random()
            phis = [
                self.poly.random(self.t, values[k])
                for k in range(secret_count)
            ]
            psis = []
            orig_poly_commitments = [
                self.poly_commit.commit(phis[k], r)
                for k in range(secret_count)
            ]
            for batch_idx in range(secret_count // (self.t + 1)):
                base_idx = batch_idx * (self.t + 1)
                known_polys = [[i + 1, phis[base_idx + i]]
                               for i in range(self.t + 1)]
                psis.extend([
                    poly_interpolate_at_x(self.poly, known_polys, i + 1)
                    for i in range(self.t + 1, self.n)
                ])
            redundant_poly_commitments = [
                self.poly_commit.commit(psis[k], r)
                for k in range(redundant_poly_count)
            ]

            ephemeral_secret_key = self.field.random()
            ephemeral_public_key = pow(self.g, ephemeral_secret_key)
            dispersal_msg_list = [None] * n
            orig_poly_witnesses = [
                self.poly_commit.double_batch_create_witness(
                    phis[i::(self.t + 1)], r) for i in range(self.t + 1)
            ]
            redundant_poly_witnesses = [
                self.poly_commit.double_batch_create_witness(
                    psis[i::(n - (self.t + 1))], r)
                for i in range(n - (self.t + 1))
            ]
            fault_i = randint(1, n - 1)
            # fault_i = 4
            fault_k = randint(1, secret_count - 1)
            for i in range(n):
                shared_key = pow(self.public_keys[i], ephemeral_secret_key)
                orig_shares = [phis[k](i + 1) for k in range(secret_count)]
                if i == fault_i:
                    orig_shares[fault_k] = ZR.random()
                # redundant_shares = [psis[k](i + 1) for k in range(redundant_poly_count)]
                # Redundant shares are not required to send.
                z = (orig_shares,
                     [orig_poly_witnesses[j][i] for j in range(self.t + 1)], [
                         redundant_poly_witnesses[j][i]
                         for j in range(n - (self.t + 1))
                     ])
                zz = SymmetricCrypto.encrypt(str(shared_key).encode(), z)
                dispersal_msg_list[i] = zz

            return dumps((orig_poly_commitments, redundant_poly_commitments,
                          ephemeral_public_key)), dispersal_msg_list
Exemple #7
0
        def _get_dealer_msg(self, value):
            fault_i = randint(0, self.n - 1)
            phi = self.poly.random(self.t, value)
            commitment, aux_poly = self.poly_commit.commit(phi)
            ephemeral_secret_key = self.field.random()
            ephemeral_public_key = pow(self.g, ephemeral_secret_key)
            z = [None] * self.n
            for i in range(self.n):
                witness = self.poly_commit.create_witness(aux_poly, i + 1)
                shared_key = pow(self.public_keys[i], ephemeral_secret_key)
                if i == fault_i:
                    z[i] = SymmetricCrypto.encrypt(
                        str(ZR.random()).encode(), ([phi(i + 1)], [witness]))
                else:
                    z[i] = SymmetricCrypto.encrypt(
                        str(shared_key).encode(), ([phi(i + 1)], [witness]))

            return dumps(([commitment], ephemeral_public_key, z))
Exemple #8
0
 def _handle_implication(self, commitments, ephemeral_public_key, j, j_sk,
                         j_z):
     """
     Handle the implication of AVSS.
     Return True if the implication is valid, False otherwise.
     """
     print("got implication")
     # discard if PKj ! = g^SKj
     if self.public_keys[j] != pow(self.g, j_sk):
         return False
     # decrypt and verify
     j_shared_key = pow(ephemeral_public_key, j_sk)
     try:
         j_shares, j_auxs = SymmetricCrypto.decrypt(
             str(j_shared_key).encode(), j_z)
     except Exception:  # TODO: specific exception
         return True
     return not self.poly_commit.batch_verify_eval(commitments, j + 1,
                                                   j_shares, j_auxs)
Exemple #9
0
 async def _handle_implication(self, avid, tag, ephemeral_public_key,
                               commitments, j, j_pk, j_k):
     """
     Handle the implication of AVSS.
     Return True if the implication is valid, False otherwise.
     """
     # discard if PKj ! = g^SKj
     if self.public_keys[j] != pow(self.g, j_pk):
         return False
     # decrypt and verify
     implicate_msg = await avid.retrieve(tag, j)
     j_shared_key = pow(ephemeral_public_key, j_pk)
     try:
         j_share, j_aux, j_witnesses = SymmetricCrypto.decrypt(
             str(j_shared_key).encode(), implicate_msg)[j_k]
     except Exception as e:  # TODO specific exception
         logger.warn("Implicate confirmed, bad encryption:", e)
         return True
     return not self.poly_commit.verify_eval(commitments[j_k], j + 1,
                                             j_share, j_aux, j_witnesses)
Exemple #10
0
    async def _process_avss_msg(self, avss_id, dealer_id, avss_msg):
        tag = f"{dealer_id}-{avss_id}-AVSS"
        send, recv = self.get_send(tag), self.subscribe_recv(tag)

        def multicast(msg):
            for i in range(self.n):
                send(i, msg)

        commitments, ephemeral_public_key, encrypted_blobs = loads(avss_msg)
        shared_key = pow(ephemeral_public_key, self.private_key)
        share_valid = True
        try:
            shares, witnesses = SymmetricCrypto.decrypt(
                str(shared_key).encode(), encrypted_blobs[self.my_id])
            if self.poly_commit.batch_verify_eval(commitments, self.my_id + 1,
                                                  shares, witnesses):
                logger.info(f"OK_timestamp: {time.time()}")
                multicast((HbAVSSMessageType.OK, ""))
            else:
                multicast((HbAVSSMessageType.IMPLICATE, self.private_key))
                share_valid = False
        except Exception:  # TODO specific exceptions
            multicast((HbAVSSMessageType.IMPLICATE, self.private_key))
            share_valid = False

        # RECEIVE LOOP
        ok_set = set()
        recovery_set = set()
        implicate_set = set()
        recovery_shares = [[] for _ in range(len(commitments))]
        sent_recovery = False
        output = False
        recovered = False
        while True:
            if len(ok_set) == 2 * self.t + 1 and share_valid and not output:
                if len(commitments) == 1:
                    self.output_queue.put_nowait(
                        (dealer_id, avss_id, int(shares[0])))
                else:
                    int_shares = [int(shares[i]) for i in range(len(shares))]
                    self.output_queue.put_nowait(
                        (dealer_id, avss_id, int_shares))
                output = True
            elif len(recovery_set) == self.t + 1 and not output:
                if len(commitments) == 1:
                    shares = [
                        self.poly.interpolate_at(recovery_shares[0],
                                                 self.my_id + 1)
                    ]
                    self.output_queue.put_nowait(
                        (dealer_id, avss_id, int(shares[0])))
                else:
                    shares = [None] * len(commitments)
                    share_ints = [None] * len(commitments)
                    for i in range(len(commitments)):
                        shares[i] = self.poly.interpolate_at(
                            recovery_shares[i], self.my_id + 1)
                        share_ints[i] = int(shares[i])
                    self.output_queue.put_nowait(
                        (dealer_id, avss_id, share_ints))
                output = True
                share_valid = True
                recovered = True
                multicast((HbAVSSMessageType.OK, ""))

            # Conditions where we can terminate
            if (len(ok_set) == self.n or len(implicate_set) >= self.t + 1
                    or len(ok_set) >= 2 * self.t + 1 and
                (sent_recovery or recovered)):
                break

            sender, avss_msg = await recv(
            )  # First value is `sid` (not true anymore?)
            if avss_msg[0] == HbAVSSMessageType.OK and sender not in ok_set:
                ok_set.add(sender)
            if (avss_msg[0] == HbAVSSMessageType.IMPLICATE
                    and sender not in implicate_set):
                implicate_set.add(sender)
            if (avss_msg[0] == HbAVSSMessageType.IMPLICATE
                    and not sent_recovery and share_valid):
                j_sk = avss_msg[1]
                j = sender
                # validate the implicate
                if not self._handle_implication(commitments,
                                                ephemeral_public_key, j, j_sk,
                                                encrypted_blobs[j]):
                    # Count an invalid implicate as an okay
                    if sender not in ok_set:
                        ok_set.add(sender)
                    continue
                sent_recovery = True
                multicast((HbAVSSMessageType.RECOVERY, self.private_key))
            if (avss_msg[0] == HbAVSSMessageType.RECOVERY and not share_valid
                    and sender not in recovery_set):
                try:
                    shares_j, auxs_j = SymmetricCrypto.decrypt(
                        str(ephemeral_public_key**avss_msg[1]).encode(),
                        encrypted_blobs[sender],
                    )  # (# noqa: E501)
                except Exception:
                    ok_set.add(sender)
                    continue
                if self.poly_commit.batch_verify_eval(commitments, sender + 1,
                                                      shares_j, auxs_j):
                    for i in range(len(commitments)):
                        recovery_shares[i].append([sender + 1, shares_j[i]])
                    recovery_set.add(sender)
Exemple #11
0
    async def _process_avss_msg(self, avss_id, dealer_id, rbc_msg, avid):
        tag = f"{dealer_id}-{avss_id}-B-AVSS"
        send, recv = self.get_send(tag), self.subscribe_recv(tag)

        def multicast(msg):
            for i in range(self.n):
                send(i, msg)

        # get phi and public key from reliable broadcast msg
        commitments, ephemeral_public_key = loads(rbc_msg)
        # retrieve the z
        dispersal_msg = await avid.retrieve(tag, self.my_id)

        secret_count = len(commitments)

        # all_encrypted_witnesses: n
        shared_key = pow(ephemeral_public_key, self.private_key)

        shares = [None] * secret_count
        auxes = [None] * secret_count
        witnesses = [None] * secret_count
        # Decrypt
        all_shares_valid = True
        try:
            all_wits = SymmetricCrypto.decrypt(
                str(shared_key).encode(), dispersal_msg)
            for k in range(secret_count):
                shares[k], auxes[k], witnesses[k] = all_wits[k]
        except ValueError as e:  # TODO: more specific exception
            logger.warn(f"Implicate due to failure in decrypting: {e}")
            all_shares_valid = False
            multicast((HbAVSSMessageType.IMPLICATE, self.private_key, 0))

        # call if decryption was successful
        if all_shares_valid:
            if not self.poly_commit.batch_verify_eval(
                    commitments, self.my_id + 1, shares, auxes, witnesses):
                all_shares_valid = False
                # Find which share was invalid and implicate
                for k in range(secret_count):
                    if not self.poly_commit.verify_eval(
                            commitments[k],
                            self.my_id + 1,
                            shares[k],
                            auxes[k],
                            witnesses[k],
                    ):  # (# noqa: E501)
                        multicast(
                            (HbAVSSMessageType.IMPLICATE, self.private_key, k))
                        break
        if all_shares_valid:
            logger.info(f"OK_timestamp: {time.time()}")
            multicast((HbAVSSMessageType.OK, ""))

        ok_set = set()
        implicate_set = set()
        r1_set = set()
        r2_set = set()
        r1_sent = r2_sent = False
        r1_phi = [None] * self.n
        r2_phi = [None] * self.n
        output = False

        while True:
            # main recv loop for Bracha-style agreement and implicate handling
            sender, avss_msg = await recv()
            # OK
            if avss_msg[0] == HbAVSSMessageType.OK and sender not in ok_set:
                ok_set.add(sender)
            # IMPLICATE
            if (avss_msg[0] == HbAVSSMessageType.IMPLICATE
                    and sender not in implicate_set):
                implicate_set.add(sender)
            if avss_msg[0] == HbAVSSMessageType.IMPLICATE and not r1_sent:
                # validate the implicate
                if not await self._handle_implication(
                        avid,
                        tag,
                        ephemeral_public_key,
                        commitments,
                        sender,
                        avss_msg[1],
                        avss_msg[2],
                ):
                    continue
                # proceed to share recovery
                logger.debug("[%d] Share recovery activated by %d", self.my_id,
                             sender)
                # setup the coordinates for interpolation
                c_coords = [None] * secret_count
                phi_coords = [None] * secret_count
                aux_coords = [None] * secret_count
                w_coords = [None] * secret_count
                for i in range(secret_count):
                    c_coords[i] = (i, commitments[i])
                    phi_coords[i] = (i, shares[i])
                    aux_coords[i] = (i, auxes[i])
                    w_coords[i] = (i, witnesses[i])
                # interpolate commitments
                interpolated_c = [None] * self.n
                for i in range(self.n):
                    interpolated_c[i] = interpolate_g1_at_x(c_coords, i)
                # if my shares are valid
                if not r1_sent and all_shares_valid:
                    r1_sent = True
                    phi_i = self.poly.interpolate(phi_coords)
                    aux_i = self.poly.interpolate(aux_coords)
                    for j in range(self.n):
                        phi_i_j = phi_i(j)
                        aux_i_j = aux_i(j)
                        w_i_j = interpolate_g1_at_x(w_coords, j)
                        send(j, (HbAVSSMessageType.RECOVERY1, phi_i_j, aux_i_j,
                                 w_i_j))
            # R1
            if avss_msg[0] == HbAVSSMessageType.RECOVERY1:
                _, phi_k_i, aux_k_i, w_k_i = avss_msg
                if self.poly_commit.verify_eval(interpolated_c[self.my_id],
                                                sender + 1, phi_k_i, aux_k_i,
                                                w_k_i):
                    r1_set.add(sender)
                    r1_phi[sender] = phi_k_i
            # R2
            if avss_msg[0] == HbAVSSMessageType.RECOVERY2:
                r2_set.add(sender)
                r2_phi[sender] = avss_msg[1]

            # enough R1 received -> proceed to R2
            if not r2_sent and len(r1_set) >= self.t + 1:
                r2_sent = True
                r1_phi_coords = [(i, r1_phi[i]) for i in range(self.n)
                                 if r1_phi[i] is not None]
                phi_i = self.poly.interpolate(r1_phi_coords)
                for j in range(self.n):
                    phi_j_i = phi_i(j)
                    send(j, (HbAVSSMessageType.RECOVERY2, phi_j_i))

            # enough R2 received -> output result
            if len(r2_set) >= 2 * self.t + 1 and not all_shares_valid:
                r2_phi_coords = [(i, r2_phi[i]) for i in range(self.n)
                                 if r2_phi[i] is not None]
                r2_phi_poly = self.poly.interpolate(r2_phi_coords)
                for k in range(secret_count):
                    shares[k] = r2_phi_poly(k)
                int_shares = [int(share) for share in shares]
                self.output_queue.put_nowait((dealer_id, avss_id, int_shares))
                output = True
                all_shares_valid = True
                multicast((HbAVSSMessageType.OK, ""))

            # if 2t+1 okay -> output shares
            if len(ok_set) >= 2 * self.t + 1:
                # output result by setting the future value
                if all_shares_valid and not output:
                    int_shares = [int(shares[i]) for i in range(len(shares))]
                    self.output_queue.put_nowait(
                        (dealer_id, avss_id, int_shares))
                    output = True

            # Conditions where we can terminate
            if (len(ok_set) == self.n or len(implicate_set) >= 2 * self.t
                    or (len(ok_set) >= 2 * self.t + 1 and r2_sent and output)):
                break
def test_encrypt_decrypt():
    key = uuid.uuid4().hex.encode("utf-8")
    plaintext = uuid.uuid4().hex
    ciphertext = SymmetricCrypto.encrypt(key, plaintext)
    plaintext_ = SymmetricCrypto.decrypt(key, ciphertext)
    assert plaintext_ == plaintext