Exemple #1
0
    def double(cls, p):
        res = [None] * 3
        if p == [FQ(0), FQ(1), FQ(0)]:
            return p

        # A = X1^2
        # B = Y1^2
        # C = B^2
        A = FQ(p[0])**2
        B = FQ(p[1])**2
        C = B**2

        # D = 2 * ((X1 + B)^2 - A - C)
        D = 2 * (((p[0] + B)**2) - A - C)
        E = 3 * A
        F = E**2

        res[0] = F - 2 * D
        eightC = C * 8

        # Y3 = E * (D - X3) - 8 * C
        res[1] = E * (D - res[0]) - eightC

        Y1Z1 = p[1] * p[2]
        res[2] = Y1Z1 * 2

        return res
Exemple #2
0
 def add(self, other):
     assert isinstance(other, Point)
     if self.x == 0 and self.y == 0:
         return other
     (u1, v1) = (self.x, self.y)
     (u2, v2) = (other.x, other.y)
     u3 = (u1 * v2 + v1 * u2) / (FQ.one() + JUBJUB_D * u1 * u2 * v1 * v2)
     v3 = (v1 * v2 - JUBJUB_A * u1 * u2) / (FQ.one() -
                                            JUBJUB_D * u1 * u2 * v1 * v2)
     return Point(u3, v3)
Exemple #3
0
    def affine(cls, p) -> "BN128":
        if p == [FQ(0), FQ(1), FQ(0)]:
            return self.zero
        else:
            z_inv = 1 / p[0]
            z2_inv = z_inv**2
            z3_inv = z_inv * z2_inv
            print("z_inv  : ", z_inv)
            print("z2_inv : ", z2_inv)
            print("z3_inv : ", z3_inv)

            res = [None] * 3

            res[0] = p[0] * z2_inv
            res[1] = p[1] * z3_inv
            res[2] = FQ(1)

            return res
Exemple #4
0
 def from_x(cls, x):
     """
     y^2 = ((a * x^2) / (d * x^2 - 1)) - (1 / (d * x^2 - 1))
     For every x coordinate, there are two possible points: (x, y) and (x, -y)
     """
     assert isinstance(x, FQ)
     xsq = x * x
     ax2 = JUBJUB_A * xsq
     dxsqm1 = prime_field_inv(JUBJUB_D * xsq - 1, JUBJUB_Q)
     ysq = dxsqm1 * (ax2 - 1)
     y = FQ(square_root_mod_prime(int(ysq), JUBJUB_Q))
     return cls(x, y)
Exemple #5
0
 def from_y(cls, y, sign=None):
     """
     x^2 = (y^2 - 1) / (d * y^2 - a)
     """
     assert isinstance(y, FQ)
     ysq = y * y
     lhs = ysq - 1
     rhs = JUBJUB_D * ysq - JUBJUB_A
     xsq = lhs / rhs
     x = FQ(square_root_mod_prime(int(xsq), JUBJUB_Q))
     if sign is not None:
         # Used for compress & decompress
         if (x.n & 1) != sign:
             x = -x
     else:
         if is_negative(x):
             x = -x
     return cls(x, y)
Exemple #6
0
def encryption_test():
    # K = k*G (pubKey: K, signKey : k, generator : G)
    #
    # Encryption
    # 1. C1 = M + r*K
    # 2. C2 = r*G
    #
    # Decryption
    # 3. M = C1 - k*C2
    #
    # why?
    # -> C1 = M + r*K
    # -> M = C1 - r*K --> It fails?
    # -> M = C1 - r*k*G
    # -> M = C1 - k*C2

    G = Point.generator()

    message = 231315 # ascii 98 = b
    message_field = FQ(message)
    M = Point.from_y(message_field)

    k = 1200

    K = G * k # K = k*G, public_key
    print("Public Key : {}".format(K))

    ### Encryption Process
    ### Message(M) is encrypted with public_key(K) and random_number(r)
    ### output : C1, C2

    r = 1929319 #random number
    print("Random Number : {}".format(r))

    C1 = M + (K*r)    # C1 = M + r*K
    C2 = G * r        # C2 = r*G

    print("C1 : {}".format(C1))
    print("C2 : {}".format(C2))

    ### Decryption Process

    decrypted_M = C1 - (C2*k); # M = C1 - k*C2
    print("Decrypted Message : {}".format(decrypted_M.y))
Exemple #7
0
    def from_hash(cls, entropy):
        """
        HashToPoint (or Point.from_hash)
        Parameters:
            entropy (bytes): input entropy provided as byte array
        Hashes the input entropy and interprets the result as the Y coordinate
        then recovers the X coordinate, if no valid point can be recovered
        Y is incremented until a matching X coordinate is found.
        The point is guaranteed to be prime order and not the identity.
        From: https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/?include_text=1
        Page 6:
           o  HashToBase(x, i).  This method is parametrized by p and H, where p
              is the prime order of the base field Fp, and H is a cryptographic
              hash function which outputs at least floor(log2(p)) + 2 bits.  The
              function first hashes x, converts the result to an integer, and
              reduces modulo p to give an element of Fp.
        """
        from hashlib import sha256

        assert isinstance(entropy, bytes)
        entropy = sha256(entropy).digest()
        entropy_as_int = int.from_bytes(entropy, "big")
        y = FQ(entropy_as_int)
        while True:
            try:
                p = cls.from_y(y)
            except SquareRootError:
                y += 1
                continue

            # Multiply point by cofactor, ensures it's on the prime-order subgroup
            p = p * JUBJUB_C

            # Verify point is on prime-ordered sub-group
            if (p * JUBJUB_L) != Point.infinity():
                raise RuntimeError("Point not on prime-ordered subgroup")

            return p
Exemple #8
0
 def decompress(cls, point):
     """
     From: https://ed25519.cr.yp.to/eddsa-20150704.pdf
     The encoding of F_q is used to define "negative" elements of F_q:
     specifically, x is negative if the (b-1)-bit encoding of x is
     lexiographically larger than the (b-1)-bit encoding of -x. In particular,
     if q is prime and the (b-1)-bit encoding of F_q is the little-endian
     encoding of {0, 1, ..., q-1}, then {1,3,5,...,q-2} are the negative element of F_q.
     This encoding is also used to define a b-bit encoding of each element `(x,y) ∈ E`
     as a b-bit string (x,y), namely the (b-1)-bit encoding of y followed by the sign bit.
     the sign bit is 1 if and only if x is negative.
     A parser recovers `(x,y)` from a b-bit string, while also verifying that `(x,y) ∈ E`,
     as follows: parse the first b-1 bits as y, compute `xx = (y^2 - 1) / (dy^2 - a)`;
     compute `x = [+ or -] sqrt(xx)` where the `[+ or -]` is chosen so that the sign of
     `x` matches the `b`th bit of the string. if `xx` is not a square then parsing fails.
     """
     if len(point) != 32:
         raise ValueError("Invalid input length for decompression")
     # y = int.from_bytes(point, "little")
     y = int.from_bytes(point, "big")
     sign = y >> 255
     y &= (1 << 255) - 1
     return cls.from_y(FQ(y), sign)
Exemple #9
0
    def add(cls, p1, p2):
        if p1 == [FQ(0), FQ(1), FQ(0)]: return p2
        if p2 == [FQ(0), FQ(1), FQ(0)]: return p1

        res = [None] * 3

        Z1Z1 = p1[2]**2
        Z2Z2 = p2[2]**2

        U1 = p1[0] * Z2Z2  #U1 = X1 * Z2Z2
        U2 = p2[0] * Z1Z1  #U2 = X2 * Z1Z1

        Z1_cubed = p1[2] * Z1Z1
        Z2_cubed = p2[2] * Z2Z2

        S1 = p1[1] * Z2_cubed  #S1 = Y1 * Z2 * Z2Z2
        S2 = p[1] * Z1_cubed  #S2 = Y2 * Z1 * Z1Z1

        if U1 == U2 and S1 == S2:
            cls.double(p1)

        H = U2 - U1

        S2_minus_S1 = S2 - S1

        I = (H * 2)**2
        J = H * I

        r = S2_minus_S1 + S2_minus_S1
        V = U1 * I

        S1_J = S1 * J

        # X3 = r^2 - J - 2 * V
        # Y3 = r * (V-X3)-2*S1*J
        # Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
        res[0] = r**2 - J - 2 * V
        res[1] = r * (V - res[0]) - (2 * S1_J)
        res[2] = ((p1[2] + p2[2])**2 - Z1Z1 - Z2Z2) * H

        return res
Exemple #10
0
    def __init__(self, g):
        self.g = g
        if len(g) == 2:
            this.g.append(FQ(1))

        self.zero = [FQ(0), FQ(1), FQ(0)]
Exemple #11
0
    #     res = FQ(0)
    #     rem = FQ(e)
    #     exp = base
    #
    #     while rem == FQ(0):
    #         if rem + FQ(0) == FQ(1):
    #             res = res + exp
    #         exp = exp ** 2
    #         rem = rem >> 1
    #
    #     return res


if __name__ == "__main__":
    # affine test : it works!
    p = [FQ(1), FQ(2), FQ(1)]
    bn = BN128(p)
    p_affine = bn.affine(p)
    print(p_affine)

    # double() test : it works!
    double_p = bn.double(p)
    print(bn.double(p))
    print(bn.double(double_p))

    # add() test : it works!
    print("bn.add(p, p) : ", bn.add(double_p, p))

    # mul_scalar test : test failed
    # p_mul = bn.mul_scalar(p, 151)
    # print(p_mul)
Exemple #12
0
    if pt is None:
        return None
    x, y = pt
    fq12_point = (FQ12([x.n] + [0] * 11), FQ12([y.n] + [0] * 11))
    return fq12_point


# Check consistency of the "line function"
one, two, three = G1, double(G1), multiply(G1, 3)
negone, negtwo, negthree = (
    multiply(G1, curve_order - 1),
    multiply(G1, curve_order - 2),
    multiply(G1, curve_order - 3),
)

assert linefunc(one, two, one) == FQ(0)
assert linefunc(one, two, two) == FQ(0)
assert linefunc(one, two, three) != FQ(0)
assert linefunc(one, two, negthree) == FQ(0)
assert linefunc(one, negone, one) == FQ(0)
assert linefunc(one, negone, negone) == FQ(0)
assert linefunc(one, negone, two) != FQ(0)
assert linefunc(one, one, one) == FQ(0)
assert linefunc(one, one, two) != FQ(0)
assert linefunc(one, one, negtwo) == FQ(0)


# Main miller loop
def miller_loop(Q: Point2D[FQ12], P: Point2D[FQ12]) -> FQ12:
    if Q is None or P is None:
        return FQ12.one()
Exemple #13
0
 def infinity():
     return Point(FQ(0), FQ(1))
Exemple #14
0
 def generator(cls):
     x = 16540640123574156134436876038791482806971768689494387082833631921987005038935
     y = 20819045374670962167435360035096875258406992893633759881276124905556507972311
     return Point(FQ(x), FQ(y))
Exemple #15
0
    FQ12,
)

Point2D = Optional[Tuple[Field,
                         Field]]  # Point at infinity is encoded as a None
Point3D = Optional[Tuple[Field, Field,
                         Field]]  # Point at infinity is encoded as a None
GeneralPoint = Union[Point2D[Field], Point3D[Field]]

# Curve order should be prime
assert pow(2, curve_order, curve_order) == 2
# Curve order should be a factor of field_modulus**12 - 1
assert (field_modulus**12 - 1) % curve_order == 0

# Curve is y**2 = x**3 + 3
b = FQ(3)
# Twisted curve over FQ**2
b2 = FQ2([3, 0]) / FQ2([9, 1])
# Extension curve over FQ**12; same b value as over FQ
b12 = FQ12([3] + [0] * 11)

# Generator for curve over FQ
G1 = (FQ(1), FQ(2))
# Generator for twisted curve over FQ2
G2 = (
    FQ2([
        10857046999023057135944570762232829481370756359578518086990519993285655852781,
        11559732032986387107991004021392285783925812861821192530917403151452391805634,
    ]),
    FQ2([
        8495653923123431417604973247489272438418190587263600148770280649306958101930,