Exemplo n.º 1
0
def mix_ciphers(ciphers_for_mixing, nr_rounds=MIN_MIX_ROUNDS,
                teller=_teller, nr_parallel=0):
    p = ciphers_for_mixing['modulus']
    g = ciphers_for_mixing['generator']
    q = ciphers_for_mixing['order']
    y = ciphers_for_mixing['public']

    original_ciphers = ciphers_for_mixing['mixed_ciphers']
    nr_ciphers = len(original_ciphers)

    teller.task('Mixing %d ciphers for %d rounds' % (nr_ciphers, nr_rounds))

    cipher_mix = {'modulus': p, 'generator': g, 'order': q, 'public': y}
    cipher_mix['original_ciphers'] = original_ciphers

    with teller.task('Producing final mixed ciphers', total=nr_ciphers):
        shuffled = shuffle_ciphers(p, g, q, y, original_ciphers, teller=teller)
        mixed_ciphers, mixed_offsets, mixed_randoms = shuffled
        cipher_mix['mixed_ciphers'] = mixed_ciphers

    total = nr_ciphers * nr_rounds
    with teller.task('Producing ciphers for proof', total=total):
        if nr_parallel > 0:
            pool = Pool(nr_parallel, Random.atfork)
            data = [
                (p, g, q, y, original_ciphers)
                for _ in range(nr_rounds)
            ]
            collections = []
            for r in pool.imap(_shuffle_ciphers, data):
                teller.advance()
                collections.append(r)
            pool.close()
            pool.join()
        else:
            collections = [shuffle_ciphers(p, g, q, y,
                                           original_ciphers, teller=teller)
                           for _ in range(nr_rounds)]

        unzipped = [list(x) for x in zip(*collections)]
        cipher_collections, offset_collections, random_collections = unzipped
        cipher_mix['cipher_collections'] = cipher_collections
        cipher_mix['random_collections'] = random_collections
        cipher_mix['offset_collections'] = offset_collections

    with teller.task('Producing cryptographic hash challenge'):
        challenge = compute_mix_challenge(cipher_mix)
        cipher_mix['challenge'] = challenge

    bits = bit_iterator(int(challenge, 16))

    with teller.task('Answering according to challenge', total=nr_rounds):
        for i, bit in zip(range(nr_rounds), bits):
            offsets = offset_collections[i]
            randoms = random_collections[i]

            if bit == 0:
                # Nothing to do, we just publish our offsets and randoms
                pass
            elif bit == 1:
                # The image is given. We now have to prove we know
                # both this image's and mixed_ciphers' offsets/randoms
                # by providing new offsets/randoms so one can reencode
                # this image to end up with mixed_ciphers.
                # original_ciphers -> image
                # original_ciphers -> mixed_ciphers
                # Provide image -> mixed_ciphers
                new_offsets = list([None]) * nr_ciphers
                new_randoms = list([None]) * nr_ciphers

                for j in range(nr_ciphers):
                    cipher_random = randoms[j]
                    cipher_offset = offsets[j]
                    mixed_random = mixed_randoms[j]
                    mixed_offset = mixed_offsets[j]

                    new_offsets[cipher_offset] = mixed_offset
                    new_random = (mixed_random - cipher_random) % q
                    new_randoms[cipher_offset] = new_random

                offset_collections[i] = new_offsets
                random_collections[i] = new_randoms
                del offsets, randoms
            else:
                m = "This should be impossible. Something is broken."
                raise AssertionError(m)

            teller.advance()
    teller.finish('Mixing')

    return cipher_mix
Exemplo n.º 2
0
def verify_cipher_mix(cipher_mix, teller=_teller, nr_parallel=0):
    try:
        p = cipher_mix['modulus']
        g = cipher_mix['generator']
        q = cipher_mix['order']
        y = cipher_mix['public']

        original_ciphers = cipher_mix['original_ciphers']
        mixed_ciphers = cipher_mix['mixed_ciphers']
        challenge = cipher_mix['challenge']
        cipher_collections = cipher_mix['cipher_collections']
        offset_collections = cipher_mix['offset_collections']
        random_collections = cipher_mix['random_collections']
    except KeyError as e:
        m = "Invalid cipher mix format"
        raise ZeusError(m, e)

    if compute_mix_challenge(cipher_mix) != challenge:
        m = "Invalid challenge"
        raise ZeusError(m)

    nr_ciphers = len(original_ciphers)
    nr_rounds = len(cipher_collections)
    teller.task('Verifying mixing of %d ciphers for %d rounds'
                 % (nr_ciphers, nr_rounds))

    if (len(offset_collections) != nr_rounds or
        len(random_collections) != nr_rounds):
        m = "Invalid cipher mix format: collections not of the same size!"
        raise ZeusError(m)

    #if not validate_cryptosystem(p, g, q, teller):
    #    m = "Invalid cryptosystem"
    #    raise AssertionError(m)

    total = nr_rounds * nr_ciphers
    with teller.task('Verifying ciphers', total=total):
        data = []
        for i, bit in zip(range(nr_rounds), bit_iterator(int(challenge, 16))):
            ciphers = cipher_collections[i]
            randoms = random_collections[i]
            offsets = offset_collections[i]
            data.append((p, g, q, y,
                         i, bit, original_ciphers,
                         mixed_ciphers, ciphers,
                         randoms, offsets))

        if nr_parallel <= 0:
            for args in data:
                verify_mix_round(*args, teller=teller)

        else:
            pool = Pool(nr_parallel, Random.atfork)
            try:
                for count in pool.imap(_verify_mix_round, data):
                    teller.advance(count)
            finally:
                pool.terminate()
                pool.join()

    teller.finish('Verifying mixing')
    return 1