Example #1
0
def scratch(puz, sk, m):
    assert len(m) == 20
    d, puzid = puz
    leaves, tree = sk
    root = tree[-1][0]

    # Draw a random nonce
    nonce = random_string(k / 8)

    # Select Q1 branches
    h1 = sha1_fixed(rzfill(puzid + root + nonce, 64))
    qinds = select_hash(h1, Q1, TREE1_HEIGHT - 1)

    leaves1 = [leaves[i] for i in qinds]
    branches1 = [merkle_select(tree, i) for i in qinds]

    # Merkle-Damgard hash
    # leaf [branch] ... leaf [branch]
    state = h1
    for leaf, branch in zip(leaves1, branches1):
        lb = [leaf] + branch
        for j in range(CIRCUITS_PER_BRANCH):
            lbh = lb[j * HASHES_PER_CIRCUIT : (j + 1) * HASHES_PER_CIRCUIT]
            state = sha1_fixed(rzfill(state + "".join(lbh), ENC_BLOCKS_PER_CIRCUIT * 64))
    h2 = state
    # Check if winner!
    if not long(binascii.hexlify(h2), base=16) < 2 ** (k - d):
        return
    # print 'h2', binascii.hexlify(h2)

    # Use H(h2|m) to select 4*Q2 more leaves
    hm = h2
    q2inds = []
    iters = int(ceil(float(4 * Q2) / (k / (TREE1_HEIGHT - 1))))
    for i in range(iters):
        hm = hash(hm + m)
        # print 'hm', binascii.hexlify(hm)
        q2inds += select_hash(hm, (k / (TREE1_HEIGHT - 1)), TREE1_HEIGHT - 1)
    q2inds = q2inds[: Q2 * 4]

    # print "[scratch] qinds:", qinds, "q2inds:", q2inds

    # Choose the first Q2 (we have all of them)
    chosen = list(q2inds)
    random.shuffle(chosen)
    chosen = set(q2inds[:Q2])
    chosen = [q for q in q2inds if q in chosen]
    leaves2 = [leaves[i] for i in chosen]
    branches2 = [merkle_select(tree, i) for i in chosen]

    ticket = root, nonce, zip(leaves1 + leaves2, branches1 + branches2), chosen
    return ticket
Example #2
0
def verify_ticket(puz, ticket, m):
    # Parse ticket as root, nonce, branches
    d, puzid = puz
    root, nonce, leavesbranches, zinds = ticket

    # Check that root selects a set of q branches
    h1 = sha1_fixed(rzfill(puzid + root + nonce, 64))
    qinds = select_hash(h1, Q1, TREE1_HEIGHT - 1)

    # Compute hashtree digest over all the data in branches
    assert len(leavesbranches) == Q1 + Q2
    assert len(qinds) + len(zinds) == Q1 + Q2
    for ind, (leaf, branch) in zip(tuple(qinds) + tuple(zinds), leavesbranches):
        assert len(branch) == TREE1_HEIGHT - 1
        assert merkle_check(hash(leaf), branch, root, ind)

    # Merkle Damgard hash over all leaves and branches
    state = h1
    for leaf, branch in leavesbranches[:Q1]:
        lb = [leaf] + branch
        for j in range(CIRCUITS_PER_BRANCH):
            lbh = lb[j * HASHES_PER_CIRCUIT : (j + 1) * HASHES_PER_CIRCUIT]
            state = sha1_fixed(rzfill(state + "".join(lbh), ENC_BLOCKS_PER_CIRCUIT * 64))
    h2 = state

    assert long(binascii.hexlify(h2), 16) < 2 ** (k - d)

    # Check that zinds are a Q2 subset of the 4Q2 chosen ones
    hm = h2
    iters = int(ceil(float(4 * Q2) / (k / (TREE1_HEIGHT - 1))))
    q2inds = []
    for i in range(iters):
        hm = hash(hm + m)
        q2inds += select_hash(hm, (k / (TREE1_HEIGHT - 1)), TREE1_HEIGHT - 1)
    q2inds = q2inds[: 4 * Q2]
    # print 'q2inds', q2inds
    assert len(zinds) == Q2
    # assert zinds == q2inds[:Q2]
    assert is_subset(zinds, q2inds)

    return True
Example #3
0
def vc_verify_ticket_full(puz, ticket, m, witnesses):
    d, puzid = puz
    ciphertext_sets, hmacs, public_value, hmacG = ticket

    assert len(witnesses) == N_CIRCUITS + 1

    for b in range(Q1 + Q2):
        for i in range(CIRCUITS_PER_BRANCH):
            ciphertexts = ciphertext_sets[b * CIRCUITS_PER_BRANCH + i]
            assert len(ciphertexts) == HASHES_PER_CIRCUIT * 20
            cblocks = sha1_fixed(rzfill(ciphertexts, ENC_BLOCKS_PER_CIRCUIT * 64))

            bi = (b << 16) + i
            bi_s = long_to_string(bi, 4)
            v_input = hash(
                (hmacs[b * CIRCUITS_PER_BRANCH + i] + hmacs[b * CIRCUITS_PER_BRANCH + i + 1] + cblocks + bi_s + hmacG)
            )

            assert vc_check_circuit_1(v_input, witnesses[b * CIRCUITS_PER_BRANCH + i])

    puzstr = long_to_string(d, 4) + puz[1]
    v_input = hash(hmacs[0] + hmacs[-1] + m + puzstr + elgamal.group_element_to_string(public_value))
    assert vc_check_circuit_final(v_input, witnesses[-1])
Example #4
0
def write_inputs(output_dir, puz, vcticket, witnesses):
    import os
    import scratch_pb2

    output_dir = output_dir + "B_c%02d_h%02d_q1%02d_q2%02d" % (HASHES_PER_CIRCUIT, TREE1_HEIGHT, Q1, Q2)
    try:
        os.makedirs(output_dir)
    except OSError:
        pass  # directory already exists

    class CircuitInput(object):
        def __init__(self, f):
            self.f = f
            self.wirecount = 0

        def write(self, s):
            assert len(s) % 4 == 0, "Only writing multiples of 32 bits"
            for i in range(len(s) / 4):
                b = s[i * 4 : (i + 1) * 4]
                ss = binascii.hexlify(b)
                self.f.write("%d %s\n" % (self.wirecount, ss))
                # print 'wrote:', self.wirecount
                self.wirecount += 1

        def close(self):
            self.f.write("%d 1\n" % (self.wirecount,))

    d, puzid = puz
    ciphertext_sets, hmacs, public_value, hmacG = vcticket

    for i, witness in enumerate(witnesses[:-1]):

        # Inner witness
        (
            root,
            bi_s,
            lbhere,
            hmacG_key,
            old_hmac,
            new_hmac,
            cblocks,
            ciphertexts,
            old_state,
            old_hmac_key,
            old_merkle_state,
            new_state,
            hmac_key,
            enc_key,
            inds_s,
        ) = witness

        # Local indices
        b = string_to_long(bi_s) >> 16
        z = (string_to_long(bi_s)) & 0xFFFF

        # Verifier input
        v_input = hash((hmacs[i] + hmacs[i + 1] + cblocks + bi_s + hmacG))

        print "inner witness[%d]: v_input:%s old_hmac:%s new_hmac:%s" % (
            i,
            binascii.hexlify(v_input),
            binascii.hexlify(old_hmac),
            binascii.hexlify(new_hmac),
        )

        # Encryptions
        ciphertexts = ciphertext_sets[i]
        cblocks = sha1_fixed(rzfill(ciphertexts, 64 * ENC_BLOCKS_PER_CIRCUIT))

        # Write the wire inputs file
        with open(os.path.join(output_dir, "wire_input_%02d.in" % i), "w") as f:
            cf = CircuitInput(f)
            # Verifier's input
            cf.write(v_input)
            # Prover's inputs
            cf.write(root)
            cf.write(enc_key)
            assert len(inds_s) == 48
            cf.write(inds_s)
            cf.write(bi_s)
            cf.write(rzfill("".join(lbhere), 20 * (HASHES_PER_CIRCUIT)))
            print binascii.hexlify(rzfill("".join(lbhere), 20 * (HASHES_PER_CIRCUIT)))
            cf.write(old_hmac)
            cf.write(new_hmac)
            cf.write(hmacG)
            cf.write(old_merkle_state)
            cf.write(hmacG_key)
            cf.write(cblocks)
            cf.write(old_state)
            cf.write(old_hmac_key)
            cf.write(new_state)
            cf.write(hmac_key)
            cf.close()
            print "hmacG", binascii.hexlify(hmacG)

    # Final Witness
    for _ in [1]:
        (
            root,
            nonce,
            hmacG,
            hmacG_key,
            first_hmac_key,
            h2,
            inds_s,
            last_hmac_key,
            hmac0,
            hmacN,
            m,
            puzstr,
            public_value,
            secret_exponent,
            secret_value,
        ) = witnesses[-1]

        gu = elgamal.g_raised_to(secret_exponent)
        hu = elgamal.h_raised_to(secret_exponent)
        assert public_value == gu
        assert secret_value == hu
        enc_key = sha1_fixed(elgamal.group_element_to_string(secret_value))

        # Check the verifier input
        v_input = hash(hmac0 + hmacN + m + puzstr + elgamal.group_element_to_string(gu))

        # Write the wire inputs file
        with open(os.path.join(output_dir, "wire_input_final.in"), "w") as f:
            cf = CircuitInput(f)
            # Verifier's input
            # cf.write(v_input)
            assert len(v_input) == 20
            # Prover's inputs
            cf.write(hmacG)
            cf.write(hmac0)
            cf.write(hmacN)
            cf.write(m)
            assert len(m) == 20
            cf.write(puzstr)
            assert len(puzstr) == 24

            cf.write(root)
            cf.write(nonce)
            cf.write(hmacG_key)
            cf.write(first_hmac_key)
            cf.write(h2)
            assert len(inds_s) == 48
            cf.write(inds_s)
            cf.write(last_hmac_key)
            print "root", binascii.hexlify(root)
            print "nonce", binascii.hexlify(nonce)
            print "hmac0", binascii.hexlify(hmac0)
            print "hmacN", binascii.hexlify(hmacN)
            # cf.write(elgamal.group_element_to_string(gu))
            # assert len(elgamal.group_element_to_string(gu)) == 128
            cf.write(elgamal.group_element_to_string(hu))
            assert len(elgamal.group_element_to_string(hu)) == 128
            bitstring = bin(secret_exponent)[2:]
            bitstring = "0" * (512 - len(bitstring)) + bitstring
            for bit in map(int, bitstring[::-1]):
                cf.write(long_to_string(bit, 4))
            cf.close()
Example #5
0
def vc_check_circuit_final(v_input, witness):

    (
        root,
        nonce,
        hmacG,
        hmacG_key,
        first_hmac_key,
        h2,
        inds_s,
        last_hmac_key,
        hmac0,
        hmacN,
        m,
        puzstr,
        public_value,
        secret_exponent,
        secret_value,
    ) = witness

    d = string_to_long(puzstr[:4])
    puzid = puzstr[4:]

    # Recompute h1 and check indices
    h1 = sha1_fixed(rzfill(puzid + root + nonce, 64))
    q1inds = select_hash(h1, Q1, TREE1_HEIGHT - 1)

    # Recompute the entire inds hash
    hm = hash(h2 + m)
    q2inds = []
    iters = int(ceil(float(4 * Q2) / (k / (TREE1_HEIGHT - 1))))
    for i in range(iters):
        hm = hash(hm + m)
        q2inds += select_hash(hm, (k / (TREE1_HEIGHT - 1)), TREE1_HEIGHT - 1)

    inds = []
    for j in range(Q1 + Q2):
        inds.append(string_to_long(inds_s[j * 2 : (j + 1) * 2]))
    inds = tuple(inds)
    assert inds[:Q1] == q1inds

    # TODO: check that Q2 is a subset of q2inds
    assert len(inds[Q1 : Q1 + Q2]) == Q2

    # Check the diffie hellman value for enc_key and secret_value
    gu = elgamal.g_raised_to(secret_exponent)
    hu = elgamal.h_raised_to(secret_exponent)
    assert secret_value == hu
    enc_key = sha1_fixed(elgamal.group_element_to_string(secret_value))
    print "h1", binascii.hexlify(h1)
    # Check v_input
    assert hmac0 == sha1_fixed(rzfill(first_hmac_key + h1 + "\0" * 20, 64))
    assert hmacN == sha1_fixed(rzfill(last_hmac_key + h2 + root, 64))

    assert hmacG == hash(hmacG_key + root + enc_key + inds_s)

    # Check the verifier input
    assert v_input == hash(hmac0 + hmacN + m + puzstr + elgamal.group_element_to_string(gu))

    # Check winning condition
    assert long(binascii.hexlify(h2), 16) < 2 ** (k - d)

    return True
Example #6
0
def vc_check_circuit_1(v_input, witness):

    # Parse witness
    (
        root,
        bi_s,
        lbhere,
        hmacG_key,
        old_hmac,
        new_hmac,
        cblocks,
        ciphertexts,
        old_state,
        old_hmac_key,
        old_merkle_state,
        new_state,
        hmac_key,
        enc_key,
        inds_s,
    ) = witness

    b = string_to_long(bi_s) >> 16
    i = string_to_long(bi_s) & 0xFFFF

    # Recompute the global HMAC
    hmacG = hash(hmacG_key + root + enc_key + inds_s)

    # Open verifier input
    assert hash((old_hmac + new_hmac + cblocks + bi_s + hmacG)) == v_input

    # Check opening of state commitment
    old_hmac_check = sha1_fixed(rzfill(old_hmac_key + old_state + old_merkle_state, 64))
    assert old_hmac_check == old_hmac

    # Check the encryption of branches
    stream = rzfill("".join(lbhere), HASHES_PER_CIRCUIT * 20)
    ciphertexts = shacal_encrypt(stream, b * HASHES_PER_CIRCUIT * CIRCUITS_PER_BRANCH + i * HASHES_PER_CIRCUIT, enc_key)
    assert cblocks == sha1_fixed(rzfill(ciphertexts, 64 * ENC_BLOCKS_PER_CIRCUIT))

    # Check the updated hash state
    stream = rzfill(old_state + "".join(lbhere), ENC_BLOCKS_PER_CIRCUIT * 64)
    if b < Q1:
        new_state_check = sha1_fixed(stream)
    else:
        new_state_check = old_state
    assert new_state == new_state_check

    # Check the incremental merkle state
    ind = string_to_long(inds_s[2 * b : 2 * (b + 1)])
    if i > 0:
        ind_copy = ind >> (i * HASHES_PER_CIRCUIT - 1)
    else:
        ind_copy = ind
    merkle_state = old_merkle_state
    for j in range(HASHES_PER_CIRCUIT):
        if i * HASHES_PER_CIRCUIT + j >= TREE1_HEIGHT:
            continue
        sibling = lbhere[j]
        if i == 0 and j == 0:
            merkle_state = hash(sibling)  # It's actually the leaf
        else:
            if not ind_copy % 2:  # left node select, sibling to the right
                merkle_state = hash(merkle_state + sibling)
            else:
                merkle_state = hash(sibling + merkle_state)
            ind_copy >>= 1
            if i * HASHES_PER_CIRCUIT + j == TREE1_HEIGHT - 1:
                assert merkle_state == root

    # Check opening of the new hmac commitment
    hmac = sha1_fixed(rzfill(hmac_key + new_state + merkle_state, 64))
    assert hmac == new_hmac

    return True
Example #7
0
def transform(puz, ticket, m, hmac_keys, secret_exponent):
    d, puzid = puz
    root, nonce, leavesbranches, chosen = ticket

    secret_value = elgamal.h_raised_to(secret_exponent)
    public_value = elgamal.g_raised_to(secret_exponent)
    enc_key = sha1_fixed(elgamal.group_element_to_string(secret_value))

    # A) Need to encrypt the root, nonce, leaves, and branches, in chunks
    # B) Need to make HMAC commitments to the internal state
    # C) Need to break the leavesQ1/branchesQ1 into chunks to be verified

    # Build an iterator over the randomness rather than counting for now
    assert len(hmac_keys) == 2 + N_CIRCUITS

    # These need to be coalesced into group elements!
    ciphertexts = []
    assert len(leavesbranches) == Q1 + Q2

    h1 = sha1_fixed(rzfill(puzid + root + nonce, 64))
    inds = select_hash(h1, Q1, TREE1_HEIGHT - 1) + tuple(chosen)
    assert len(inds) == Q1 + Q2
    inds_s = rzfill("".join(long_to_string(ind, 2) for ind in inds), 48)

    # The first randomness is used as IV for the hashchain over leaves
    state = h1

    # Ciphertext accumulators, as well as the set of ciphertexts
    cipher_accs = []
    ciphertext_sets = []

    # Commitments to local state
    hmacs = []

    # Initialize hmacs with root, empty state/inds
    hmac = sha1_fixed(rzfill(hmac_keys[0] + h1 + "\0" * 20, 64))
    hmacs.append(hmac)

    # Commitments to glob
    hmacG = hash((hmac_keys[-1] + root + enc_key + inds_s))

    # Witnesses
    witnesses = []
    merkle_state = "\0" * 20
    # First prepare the encryptions
    for b in range(Q1 + Q2):
        leaf, branch = leavesbranches[b]
        leafbranch = [leaf] + branch
        ind = inds[b]
        for i in range(CIRCUITS_PER_BRANCH):
            # qhere is the number of branches to process here
            lbhere = leafbranch[HASHES_PER_CIRCUIT * i : HASHES_PER_CIRCUIT * (i + 1)]
            stream = rzfill(state + "".join(lbhere), ENC_BLOCKS_PER_CIRCUIT * 64)

            # Update the state
            old_state = state
            if b < Q1:
                state = sha1_fixed(stream)
            # Encrypt using SHACAL, then pad to multiple of 512 bits
            stream = rzfill("".join(lbhere), HASHES_PER_CIRCUIT * 20)
            ciphertexts = shacal_encrypt(
                stream, b * HASHES_PER_CIRCUIT * CIRCUITS_PER_BRANCH + i * HASHES_PER_CIRCUIT, enc_key
            )
            assert len(ciphertexts) == HASHES_PER_CIRCUIT * 20
            ciphertext_sets.append(ciphertexts)

            # Now we need to hash over the ciphertexts used in this circuit
            cipher_accs.append(sha1_fixed(rzfill(ciphertexts, ENC_BLOCKS_PER_CIRCUIT * 64)))

            # Finally we need to prepare the auxiliary merkle tree information
            if i > 0:
                ind_copy = ind >> (i * HASHES_PER_CIRCUIT - 1)
            else:
                ind_copy = ind

            old_merkle_state = merkle_state
            for j in range(HASHES_PER_CIRCUIT):
                if i * HASHES_PER_CIRCUIT + j >= TREE1_HEIGHT:
                    continue
                sibling = lbhere[j]
                if i == 0 and j == 0:
                    merkle_state = hash(sibling)  # It's actually the leaf
                else:
                    if not ind_copy % 2:  # left node select, sibling to the right
                        merkle_state = hash(merkle_state + sibling)
                    else:
                        merkle_state = hash(sibling + merkle_state)
                    ind_copy >>= 1
                if i * HASHES_PER_CIRCUIT + j == TREE1_HEIGHT - 1:
                    assert merkle_state == root
            # Finally, we must collect the root, state, index accumulator, into
            # an hmac commitment

            hmac = sha1_fixed(rzfill(hmac_keys[b * CIRCUITS_PER_BRANCH + i + 1] + state + merkle_state, 64))
            hmacs.append(hmac)

            witness = (
                root,
                long_to_string((b << 16) + i, 4),
                lbhere,
                hmac_keys[-1],
                hmacs[-2],
                hmacs[-1],
                cipher_accs[-1],
                ciphertexts,
                old_state,
                hmac_keys[b * CIRCUITS_PER_BRANCH + i],
                old_merkle_state,
                state,
                hmac_keys[b * CIRCUITS_PER_BRANCH + i + 1],
                enc_key,
                inds_s,
            )
            witnesses.append(witness)

    # Verifier information
    verifier_data = ciphertext_sets, hmacs, public_value, hmacG

    # Witness information
    puzstr = long_to_string(d, 4) + puzid
    last_witness = (
        root,
        nonce,
        hmacG,
        hmac_keys[-1],
        hmac_keys[0],
        state,
        inds_s,
        hmac_keys[-2],
        hmacs[0],
        hmacs[-1],
        m,
        puzstr,
        public_value,
        secret_exponent,
        secret_value,
    )
    witnesses.append(last_witness)
    return verifier_data, witnesses