Example #1
0
def untwist(P):
    q = P.X.q
    root = Fq6(Fq2.zero(q), Fq2.one(q), Fq2.zero(q))
    zero = Fq6.zero(q)
    omega2 = Fq12(root, zero)
    omega3 = Fq12(zero, root)
    return EC.from_affine(omega2.inverse() * P.x, omega3.inverse() * P.y)
Example #2
0
def twist(P):
    q = P.X.q
    root = Fq6(Fq2.zero(q), Fq2.one(q), Fq2.zero(q))
    zero = Fq6.zero(q)
    omega2 = Fq12(root, zero)
    omega3 = Fq12(zero, root)
    c0 = omega2 * P.x
    c1 = omega3 * P.y
    return TwistedEC.from_affine(c0.c0.c0, c1.c0.c0)
Example #3
0
def untwist(point: AffinePoint, ec=default_ec) -> AffinePoint:
    """
    Given a point on G2 on the twisted curve, this converts it's
    coordinates back from Fq2 to Fq12. See Craig Costello book, look
    up twists.
    """
    f = Fq12.one(ec.q)
    wsq = Fq12(ec.q, f.root, Fq6.zero(ec.q))
    wcu = Fq12(ec.q, Fq6.zero(ec.q), f.root)
    return AffinePoint(point.x / wsq, point.y / wcu, False, ec)
Example #4
0
def twist(point: AffinePoint, ec=default_ec_twist) -> AffinePoint:
    """
    Given an untwisted point, this converts it's
    coordinates to a point on the twisted curve. See Craig Costello
    book, look up twists.
    """
    f = Fq12.one(ec.q)
    wsq = Fq12(ec.q, f.root, Fq6.zero(ec.q))
    wcu = Fq12(ec.q, Fq6.zero(ec.q), f.root)
    new_x = point.x * wsq
    new_y = point.y * wcu
    return AffinePoint(new_x, new_y, False, ec)
Example #5
0
def test_fields():
    a = Fq(17, 30)
    b = Fq(17, -18)
    c = Fq2(17, a, b)
    d = Fq2(17, a + a, -5)
    e = c * d
    f = e * d
    assert f != e
    e_sq = e * e
    e_sqrt = e_sq.modsqrt()
    assert pow(e_sqrt, 2) == e_sq

    a2 = Fq(
        172487123095712930573140951348,
        3012492130751239573498573249085723940848571098237509182375,
    )
    b2 = Fq(172487123095712930573140951348, 3432984572394572309458723045723849)
    c2 = Fq2(172487123095712930573140951348, a2, b2)
    assert b2 != c2

    g = Fq6(17, c, d, d * d * c)
    h = Fq6(17, a + a * c, c * b * a, b * b * d * 21)
    i = Fq12(17, g, h)
    assert ~(~i) == i
    assert (~(i.root)) * i.root == Fq6.one(17)
    x = Fq12(17, Fq6.zero(17), i.root)
    assert (~x) * x == Fq12.one(17)

    j = Fq6(17, a + a * c, Fq2.zero(17), Fq2.zero(17))
    j2 = Fq6(17, a + a * c, Fq2.zero(17), Fq2.one(17))
    assert j == (a + a * c)
    assert j2 != (a + a * c)
    assert j != j2

    # Test frob_coeffs
    one = Fq(default_ec.q, 1)
    two = one + one
    a = Fq2(default_ec.q, two, two)
    b = Fq6(default_ec.q, a, a, a)
    c = Fq12(default_ec.q, b, b)
    for base in (a, b, c):
        for expo in range(1, base.extension):
            assert base.qi_power(expo) == pow(base, pow(default_ec.q, expo))
Example #6
0
def _miller_loop(T, P, Q):
    if len(P) == 3:
        P = from_jacobian(P)
    res_num = Fq12.one(p)
    res_den = Fq12.one(p)
    R = Q
    T_bits = [1 if b == '1' else 0
              for b in bin(T)[3:]]  # all except MSB in MSB-to-LSB order
    for b in T_bits:
        (d_num, d_den) = _double_eval(R, P)
        res_num = pow(res_num, 2) * d_num
        res_den = pow(res_den, 2) * d_den
        R = point_double(R)
        if b:
            (a_num, a_den) = _add_eval(R, Q, P)
            res_num = res_num * a_num
            res_den = res_den * a_den
            R = point_add(R, Q)
    return res_num / res_den
Example #7
0
 def pop_verify(pk: JacobianPoint, proof: JacobianPoint) -> bool:
     try:
         proof.check_valid()
         pk.check_valid()
         q = g2_map(bytes(pk), pop_scheme_pop_dst)
         one = Fq12.one(default_ec.q)
         pairing_result = ate_pairing_multi([pk, G1Generator().negate()],
                                            [q, proof])
         return pairing_result == one
     except AssertionError:
         return False
Example #8
0
def ate_pairing_multi(Ps, Qs, ec=default_ec):
    """
    Computes multiple pairings at once. This is more efficient,
    since we can multiply all the results of the miller loops,
    and perform just one final exponentiation.
    """
    t = default_ec.x + 1
    T = abs(t - 1)
    prod = Fq12.one(ec.q)
    for i in range(len(Qs)):
        prod *= miller_loop(T, Ps[i], Qs[i], ec)
    return final_exponentiation(prod, ec)
Example #9
0
def core_verify_mpl(pk: JacobianPoint, message: bytes,
                    signature: JacobianPoint, dst: bytes) -> bool:
    try:
        signature.check_valid()
        pk.check_valid()
    except AssertionError:
        return False
    q = g2_map(message, dst)
    one = Fq12.one(default_ec.q)
    pairing_result = ate_pairing_multi([pk, G1Generator().negate()],
                                       [q, signature])
    return pairing_result == one
Example #10
0
    def setUp(self):
        self.a1 = Fq(3, 11)
        self.b1 = Fq(4, 11)
        self.c1 = Fq(7, 11)
        self.d1 = Fq(12, 11)
        self.e1 = Fq(2, 11)
        self.f1 = Fq(9, 11)
        self.g1 = Fq(6, 11)

        self.a2 = Fq2(self.a1, self.b1)
        self.b2 = Fq2(self.b1, self.c1)
        self.c2 = Fq2(self.c1, self.d1)
        self.d2 = Fq2(self.d1, self.e1)
        self.e2 = Fq2(self.e1, self.f1)
        self.f2 = Fq2(self.f1, self.g1)

        self.a6 = Fq6(self.a2, self.b2, self.c2)
        self.b6 = Fq6(self.b2, self.c2, self.d2)
        self.c6 = Fq6(self.d2, self.e2, self.f2)

        self.a12 = Fq12(self.a6, self.b6)
        self.b12 = Fq12(self.b6, self.c6)
Example #11
0
    def verify(self):
        """
        This implementation of verify has several steps. First, it
        reorganizes the pubkeys and messages into groups, where
        each group corresponds to a message. Then, it checks if the
        siganture has info on how it was aggregated. If so, we
        exponentiate each pk based on the exponent in the AggregationInfo.
        If not, we find public keys that share messages with others,
        and aggregate all of these securely (with exponents.).
        Finally, since each public key now corresponds to a unique
        message (since we grouped them), we can verify using the
        distinct verification procedure.
        """
        message_hashes = self.aggregation_info.message_hashes
        public_keys = self.aggregation_info.public_keys
        assert (len(message_hashes) == len(public_keys))

        hash_to_public_keys = {}
        for i in range(len(message_hashes)):
            if message_hashes[i] in hash_to_public_keys:
                hash_to_public_keys[message_hashes[i]].append(public_keys[i])
            else:
                hash_to_public_keys[message_hashes[i]] = [public_keys[i]]

        final_message_hashes = []
        final_public_keys = []
        ec = public_keys[0].value.ec
        for message_hash, mapped_keys in hash_to_public_keys.items():
            dedup = list(set(mapped_keys))
            public_key_sum = JacobianPoint(Fq.one(ec.q), Fq.one(ec.q),
                                           Fq.zero(ec.q), True, ec)
            for public_key in dedup:
                try:
                    exponent = self.aggregation_info.tree[(message_hash,
                                                           public_key)]
                    public_key_sum += (public_key.value * exponent)
                except KeyError:
                    return False
            final_message_hashes.append(message_hash)
            final_public_keys.append(public_key_sum.to_affine())

        mapped_hashes = [
            hash_to_point_prehashed_Fq2(mh) for mh in final_message_hashes
        ]

        g1 = Fq(default_ec.n, -1) * generator_Fq()
        Ps = [g1] + final_public_keys
        Qs = [self.value.to_affine()] + mapped_hashes
        res = ate_pairing_multi(Ps, Qs, default_ec)
        return res == Fq12.one(default_ec.q)
Example #12
0
def millers_alg(P, Q):
    R = Q
    f = Fq12.one(params.q)
    for r_i in bin(params.BLS_x)[3:]:
        l_RR = line(R, R, P)
        f = f.square() * l_RR
        R *= 2
        if r_i == '1':
            l_RQ = line(R, Q, P)
            f *= l_RQ
            R += Q
    if params.BLS_negative:
        f = -f
    return f
Example #13
0
def core_aggregate_verify(pks: List[JacobianPoint], ms: List[bytes],
                          signature: JacobianPoint, dst: bytes) -> bool:
    if len(pks) != len(ms) or len(pks) < 1:
        return False
    try:
        signature.check_valid()
        qs = [signature]
        ps = [G1Generator().negate()]
        for i in range(len(pks)):
            pks[i].check_valid()
            qs.append(g2_map(ms[i], dst))
            ps.append(pks[i])
        return Fq12.one(default_ec.q) == ate_pairing_multi(ps, qs)

    except AssertionError:
        return False
Example #14
0
    def verify(self, message_hashes, public_keys):
        """
        Verifies messages using the prepend method. It prepends public keys
        to message hashes before verifying.
        """
        assert (len(message_hashes) == len(public_keys))
        mapped_hashes = [
            hash_to_point_prehashed_Fq2(
                hash256(public_keys[i].serialize() + message_hashes[i]))
            for i in range(len(message_hashes))
        ]
        keys = [pk.value.to_affine() for pk in public_keys]

        g1 = Fq(default_ec.n, -1) * generator_Fq()
        Ps = [g1] + keys
        Qs = [self.value.to_affine()] + mapped_hashes
        res = ate_pairing_multi(Ps, Qs, default_ec)
        return res == Fq12.one(default_ec.q)
Example #15
0
def miller_loop(T, P, Q, ec=default_ec):
    """
    Performs a double and add algorithm for the ate pairing. This algorithm
    is taken from Craig Costello's "Pairing for Beginners".
    """
    T_bits = int_to_bits(T)
    R = Q
    f = Fq12.one(ec.q)  # f is an element of Fq12
    for i in range(1, len(T_bits)):
        # Compute sloped line lrr
        lrr = double_line_eval(R, P, ec)
        f = f * f * lrr

        R = 2 * R
        if T_bits[i] == 1:
            # Compute sloped line lrq
            lrq = add_line_eval(R, Q, P, ec)
            f = f * lrq

            R = R + Q
    return f
Example #16
0
def multi_pairing(Ps, Qs):
    assert all(isinstance(pp, Fq) for P in Ps for pp in P)
    assert all(isinstance(pp, Fq2) for Q in Qs for pp in Q)
    return _final_exp(
        reduce(mul, (_miller_loop(abs(ell_u), P, Q) for (P, Q) in zip(Ps, Qs)),
               Fq12.one(p)))
Example #17
0
# Changes from the original version:
# * uses curve impl from curve_ops
# * only supports BLS12-381
# * Miller loop implementation avoids computing inversions
#
# (C) 2019 Riad S. Wahby <*****@*****.**>

from functools import reduce
from operator import mul

from consts import p, ell_u, k_final
from curve_ops import from_jacobian, point_double, point_add, to_coZ
from fields import Fq, Fq2, Fq6, Fq12

# constants for untwisting
ut_root = Fq12.one(p).root
ut_wsq_inv = ~Fq12(p, ut_root, Fq6.zero(p))
ut_wcu_inv = ~Fq12(p, Fq6.zero(p), ut_root)
del ut_root


def _untwist(R):
    assert all(isinstance(pp, Fq2) for pp in R)
    (x, y, z) = R
    return (x * ut_wsq_inv, y * ut_wcu_inv, z)


def _double_eval(R, P):
    (xP, yP) = P
    (xR, yR, zR) = _untwist(R)
    zR3 = pow(zR, 3)