예제 #1
0
def recoverable(ot_key, tracking_key):
    """Takes a onetime key and a tracking key and returns if
    the private onetime key is recoverable.

    >>> longterm_key = keygen()
    >>> longterm_pub = longterm_key[1]
    >>> ot_key = generate_ot_key(longterm_pub)
    >>> trackingkey = key_to_trackingkey(longterm_key)

    >>> recoverable(ot_key, trackingkey)
    True

    >>> wrong_lt_key = keygen()
    >>> wrong_lt_pub = wrong_lt_key[1]
    >>> wrong_trackingkey = key_to_trackingkey(wrong_lt_key)
    >>> recoverable(ot_key, wrong_trackingkey)
    False
    """
    (ot_pubkey, dh_key) = ot_key
    (ot_pubkey, dh_key) = (binascii.unhexlify(ot_pubkey), binascii.unhexlify(dh_key))
    (a, B) = tracking_key
    hashval = ietf_ed25519.sha512(
                ietf_ed25519.point_compress(
                  ietf_ed25519.point_mul(
                      int(a, 16),
                      ietf_ed25519.point_decompress(dh_key))))
    first = ietf_ed25519.point_mul(
                int.from_bytes(hashval, "little"),
                ietf_ed25519.G)
    second = ietf_ed25519.point_decompress(binascii.unhexlify(B))
    key_ = ietf_ed25519.point_compress(
            ietf_ed25519.point_add(first, second))
    return ot_pubkey == key_
예제 #2
0
def verify(public_keys, msg, signature):
    """Checks if a LWW-ringsignature is valid.

    >>> (sec, pub) = keygen()
    >>> public_keys = [pub]
    >>> m = "some message"
    >>> sig = ringsign(public_keys, sec, m)
    >>> verify(public_keys, m, sig)
    True

    >>> public_keys = [keygen()[1] for i in range(3)]
    >>> (sec, pub) = keygen()
    >>> public_keys.append(pub)
    >>> m = "some message"
    >>> sig = ringsign(public_keys, sec, m)
    >>> verify(public_keys, m, sig)
    True
    >>> verify(public_keys, "wrong message", sig)
    False
    """
    # Typechecks for sig
    assert isinstance(signature, tuple)
    assert isinstance(signature[1], int)
    assert isinstance(signature[2], list)
    # The public_keys need to be sorted, since we need an ordering for
    # verification.
    list.sort(public_keys)
    ringsize = len(public_keys)
    L = [0 for i in range(ringsize)]
    R = [0 for i in range(ringsize)]
    c = [0 for i in range(ringsize + 1)]
    (key_image, c[0], s) = signature
    # check if the keyimage is in the subgroup generated by G
    key_image = binascii.unhexlify(key_image)
    if not ietf_ed25519.point_equal(
            ietf_ed25519.point_mul(ietf_ed25519.q,
                                   ietf_ed25519.point_decompress(key_image)),
        (0, 1, 1, 0)):
        return False
    # recover all the c
    for i in range(ringsize):
        L[i] = ietf_ed25519.point_add(
            ietf_ed25519.point_mul(s[i], ietf_ed25519.G),
            ietf_ed25519.point_mul(
                c[i],
                ietf_ed25519.point_decompress(
                    binascii.unhexlify(public_keys[i]))))
        L[i] = ietf_ed25519.point_compress(L[i])
        R[i] = ietf_ed25519.point_add(
            ietf_ed25519.point_mul(
                s[i],
                H_P(
                    ietf_ed25519.point_decompress(
                        binascii.unhexlify(public_keys[i])))),
            ietf_ed25519.point_mul(c[i],
                                   ietf_ed25519.point_decompress(key_image)))
        R[i] = ietf_ed25519.point_compress(R[i])
        c[i + 1] = sha512_modp(str.encode(msg) + L[i] + R[i])
    # Is the ring closed correctly?
    return c[ringsize] == c[0]
예제 #3
0
def recover_sec_key(ot_key, keypair):
    """Takes a onetime public key and a keypair and recovers the
    onetime secret key if possible.

    >>> longterm_key = keygen()
    >>> longterm_pub = longterm_key[1]
    >>> ot_key = generate_ot_key(longterm_pub)
    >>> (ot_pubkey, dh_key) = ot_key
    >>> trackingkey = key_to_trackingkey(longterm_key)

    >>> recovered_sec_key = recover_sec_key(ot_key, longterm_key)
    >>> lww_signature.secret_to_public(recovered_sec_key) == ot_pubkey
    True
    """
    (ot_pubkey, dh_key) = ot_key
    ((a, b), (A, B)) = keypair

    first = ietf_ed25519.sha512(
                ietf_ed25519.point_compress(
                  ietf_ed25519.point_mul(
                      int(a, 16),
                      ietf_ed25519.point_decompress(binascii.unhexlify(dh_key)))))
    first = int.from_bytes(first, "little")
    second = int(b, 16)
    ot_sec_key = first + second
    ot_sec_key = hex(ot_sec_key)
    # Check correctness
    assert(ot_pubkey == lww_signature.secret_to_public(ot_sec_key))
    return ot_sec_key
예제 #4
0
def H_P(P):
    """Hash function returning a point.
    Note that the intuitive idea of computing hash(P)*G is insecure,
    since this is not indifferentiable from a random oracle. We know
    the discrete log and in the case of the LWW-signature we ca
    cancel the anonymity property.

    Instead we compute hash(P)+i for increasing i until it is
    a valid point in the subgroup generated by G (not only on the
    curve).
    This is comparable to the algorithm in Ben Lynn's thesis, where he
    computes H(P) and tries to find a point on the curve with this
    x-coordinate. If he cannot solve for the -coordinate, he increases
    H(P) by 1.

    >>> Neutral = [0,1,1,0]
    >>> H_P(Neutral) # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
    (4645..., 3154...)
    """
    hash = hashlib.sha256(ietf_ed25519.point_compress(P)).digest()
    point = ietf_ed25519.point_decompress(hash)
    while not point or not ietf_ed25519.point_equal(
            ietf_ed25519.point_mul(ietf_ed25519.q, point), (0, 1, 1, 0)):
        # repeat if the results of the hash s not a valid point.
        # or if the point is not in the subgroup generated by g.
        # i.e., check that the order of the point is the order of g
        num = int.from_bytes(hash, "little") + 1
        hash = int.to_bytes(num, 32, "little")
        point = ietf_ed25519.point_decompress(hash)
    return point
예제 #5
0
def keyimage(secret):
    """Returns the keyimage of the secret key. This can be used for
    linking two signatures.
    """
    secret_as_int = int(secret, 16)
    public = ietf_ed25519.point_mul(secret_as_int, ietf_ed25519.G)
    solution = ietf_ed25519.point_mul(secret_as_int, H_P(public))
    return ietf_ed25519.point_compress(solution)
예제 #6
0
def secret_to_public(secret):
    """Given a secret key this returns the public key.

    >>> (sec, pub) = keygen()
    >>> secret_to_public(sec) == pub
    True
    """
    secret_as_int = int(secret, 16)
    return binascii.hexlify(
        ietf_ed25519.point_compress(
            ietf_ed25519.point_mul(secret_as_int, ietf_ed25519.G))).decode()
예제 #7
0
def generate_ot_key(public_key, nonce=None):
    """Derives a onetime publickey.
    The corresponding onetime private key can only be recovered with
    knowledge of the private_key of the public_key.
    More exactly the output is (ot_pubkey, dh_key), where dh_key and
    the private key corresponding to the public_key in the input are
    needed to compute ot_privkey, the onetime private key.

    The nonce should be unique modulo the group order and can be
    reused for different public keys. It will be generated
    automaticaly if not set.

    >>> import os
    >>> nonce = os.urandom(32)
    >>> (_, pk) = keygen()
    >>> ot_key = generate_ot_key(pk, nonce)

    >>> (_, pk) = keygen()
    >>> ot_key = generate_ot_key(pk)
    """
    if not nonce:
        nonce = os.urandom(32)
    (A, B) = public_key
    (A, B) = (binascii.unhexlify(A), binascii.unhexlify(B))
    nonce = int.from_bytes(nonce, "little") % ietf_ed25519.q
    hashval = ietf_ed25519.sha512(
                ietf_ed25519.point_compress(
                  ietf_ed25519.point_mul(
                      nonce,
                      ietf_ed25519.point_decompress(A))))
    first = ietf_ed25519.point_mul(
                int.from_bytes(hashval, "little"),
                ietf_ed25519.G)
    second = ietf_ed25519.point_decompress(B)
    ot_pubkey = ietf_ed25519.point_add(first, second)
    dh_key = ietf_ed25519.point_mul(nonce, ietf_ed25519.G)
    # In the Cryptonote Whitepaper dh_key is called R
    # Next we compress the points
    ot_pubkey = binascii.hexlify(ietf_ed25519.point_compress(ot_pubkey)).decode()
    dh_key = binascii.hexlify(ietf_ed25519.point_compress(dh_key)).decode()
    return (ot_pubkey, dh_key)
예제 #8
0
def ringsign(public_keys, secret, msg):
    """Returns a LWW-ringsignature.
    public_keys also contains the public key of the signer.
    We return the signature. Since we need always the same ordering on
    the public keys, we will order them before signing.

    >>> public_keys = [keygen()[1] for i in range(3)]
    >>> (sec, pub) = keygen()
    >>> public_keys.append(pub)
    >>> m = "some message"
    >>> signature = ringsign(public_keys, sec, m)
    """
    pub = secret_to_public(secret)
    list.sort(public_keys)
    # we sort the list, since the order is important
    signindex = public_keys.index(pub)
    key_image = keyimage(secret)
    secret_as_int = int(secret, 16)
    # signindex is the index where we start computing the signature
    # aka the index where we know the corresponding privkey
    ringsize = len(public_keys)
    L = [0 for i in range(ringsize)]
    R = [0 for i in range(ringsize)]
    c = [0 for i in range(ringsize)]
    alpha = random.SystemRandom().randrange(ietf_ed25519.p)
    s = [
        random.SystemRandom().randrange(ietf_ed25519.q)
        for i in range(ringsize)
    ]
    L[signindex] = ietf_ed25519.point_mul(alpha, ietf_ed25519.G)
    L[signindex] = ietf_ed25519.point_compress(L[signindex])
    R[signindex] = ietf_ed25519.point_mul(
        alpha,
        H_P(
            ietf_ed25519.point_decompress(
                binascii.unhexlify(public_keys[signindex]))))
    R[signindex] = ietf_ed25519.point_compress(R[signindex])
    c[(signindex + 1) %
      ringsize] = sha512_modp(str.encode(msg) + L[signindex] + R[signindex])
    # iterate through the other indices
    for i in [
            j % ringsize for j in range(signindex + 1, signindex + ringsize)
    ]:
        L[i] = ietf_ed25519.point_add(
            ietf_ed25519.point_mul(s[i], ietf_ed25519.G),
            ietf_ed25519.point_mul(
                c[i],
                ietf_ed25519.point_decompress(
                    binascii.unhexlify(public_keys[i]))))
        L[i] = ietf_ed25519.point_compress(L[i])
        R[i] = ietf_ed25519.point_add(
            ietf_ed25519.point_mul(
                s[i],
                H_P(
                    ietf_ed25519.point_decompress(
                        binascii.unhexlify(public_keys[i])))),
            ietf_ed25519.point_mul(c[i],
                                   ietf_ed25519.point_decompress(key_image)))
        R[i] = ietf_ed25519.point_compress(R[i])
        c[(i + 1) % ringsize] = sha512_modp(str.encode(msg) + L[i] + R[i])
    # stitch the ring together
    s[signindex] = (alpha - c[signindex] * secret_as_int) % ietf_ed25519.q
    signature = (binascii.hexlify(key_image).decode(), c[0], s)
    # validate if the computed signature is correct
    assert (verify(public_keys, msg, signature))
    return signature