def __init__(self, A=1, C=1): #, Ap24 = None, Am24 = None, C24 = None, ap24 = None if isinstance(A, GFp2element): self.A = A else: self.A = GFp2element(A, 0) if isinstance(C, GFp2element): self.C = C else: self.C = GFp2element(C, 0) self.Ap24 = self.A + self.C * 2 self.Am24 = self.A - self.C * 2 self.C24 = self.C * 4 self.ap24 = self.Ap24 // self.C
def seta(self, p, q, d): """ Recover Montgomery curve coefficient A as well as aux curve constants from P, Q, P-Q x-coordinates Alg. 10 in [SIKE] :param p: :param q: :param d: :return: None """ t1 = p + q t0 = p * q A = d * t1 A = A + t0 t0 = t0 * d A = A - 1 t0 = t0 + t0 t1 = t1 + d t0 = t0 + t0 A = A * A t0 = t0.modinv() A = A * t0 A = A - t1 self.A = A self.C = GFp2element(1) self.Ap24 = self.A + self.C * 2 self.Am24 = self.A - self.C * 2 self.C24 = self.C * 4 self.ap24 = self.Ap24 // self.C
def __init__(self, X, Z, parent): self.parent = parent assert (isinstance(X, GFp2element)) self.X = X # self.Y = Y if not Z is None: self.Z = Z else: self.Z = GFp2element(1)
def ladder3pt(self, m, xP, xQ, xD): """ Montgomery's ladder. Calculates x(P+[m]Q) given m and x-coordinates of P, Q, D=Q-P Alg. 9 in [SIKE] :param m: :param xP: :param xQ: :param xD: :return: """ p0 = MontgomeryPoint(xQ, GFp2element(1), self) p1 = MontgomeryPoint(xP, GFp2element(1), self) p2 = MontgomeryPoint(xD, GFp2element(1), self) self.ap24 = (self.A + 2) // 4 while m > 0: if m % 2 == 1: [p0, p1] = self.xdbladd(p0, p1, p2) else: [p0, p2] = self.xdbladd(p0, p2, p1) m = m // 2 return p1
def ParseParameters(params): global p, e2, e3, f, xp2, xq2, xr2, xp3, xq3, xr3, A, C, E0 e2 = params['eA'] e3 = params['eB'] f = params['f'] # Very first step -- initialization of the modulus modulo_initialize((2**e2) * (3**e3) * f - 1) A = GFp2element(params['A'][0], params['A'][1]) E0 = MontgomeryCurve(A, GFp2element(1)) xp2 = GFp2element(params['xp2'][0], params['xp2'][1]) xq2 = GFp2element(params['xq2'][0], params['xq2'][1]) xr2 = GFp2element(params['xr2'][0], params['xr2'][1]) xp3 = GFp2element(params['xp3'][0], params['xp3'][1]) xq3 = GFp2element(params['xq3'][0], params['xq3'][1]) xr3 = GFp2element(params['xr3'][0], params['xr3'][1])
def iso3e(self, e3, S1, X11=None, X22=None, X33=None): """ Compute and optionally evaluate a 3^e-isogeny Alg. 18 from [SIKE] :param e3: :param S1: :param X11: :param X22: :param X33: :return: """ S = S1 if not X11 is None: X1 = MontgomeryPoint(X11, GFp2element(1), self) else: X1 = None if not X22 is None: X2 = MontgomeryPoint(X22, GFp2element(1), self) else: X2 = None if not X33 is None: X3 = MontgomeryPoint(X33, GFp2element(1), self) else: X3 = None curve = None for e in range(e3 - 1, -1, -1): # T = S.mul3e(e) [curve, K1, K2] = self.iso3_curve(T) if not e == 0: S = self.iso3_eval(K1, K2, S, curve) if not X1 is None: X1 = self.iso3_eval(K1, K2, X1, curve) if not X2 is None: X2 = self.iso3_eval(K1, K2, X2, curve) if not X3 is None: X3 = self.iso3_eval(K1, K2, X3, curve) return [curve, X1, X2, X3]
def iso2e(self, e2, S1, X11=None, X22=None, X33=None): """ Compute and optionally evaluate a 2^e2-isogeny :param e2: :param S1: :param X11: :param X22: :param X33: :return: """ S = S1 if not X11 is None: X1 = MontgomeryPoint(X11, GFp2element(1), self) else: X1 = None if not X22 is None: X2 = MontgomeryPoint(X22, GFp2element(1), self) else: X2 = None if not X33 is None: X3 = MontgomeryPoint(X33, GFp2element(1), self) else: X3 = None curve = None for e in range(e2 - 1, -1, -1): T = S.mul2e(e) curve = self.iso2_curve(T) if not e == 0: S = self.iso2_eval(T, S, curve) if not X1 is None: X1 = self.iso2_eval(T, X1, curve) if not X2 is None: X2 = self.iso2_eval(T, X2, curve) if not X3 is None: X3 = self.iso2_eval(T, X3, curve) return [curve, X1, X2, X3]
def iso2eby4(self, e2, S, X11=None, X22=None, X33=None): """ Compute and optionally evaluate a 2^e2-isogeny Alg. 17 from [SIKE] :param e2: :param S1: :param X11: :param X22: :param X33: :return: """ if not X11 is None: X1 = MontgomeryPoint(X11, GFp2element(1), self) else: X1 = None if not X22 is None: X2 = MontgomeryPoint(X22, GFp2element(1), self) else: X2 = None if not X33 is None: X3 = MontgomeryPoint(X33, GFp2element(1), self) else: X3 = None curve = None for e in range(e2 - 2, -2, -2): T = S.mul2e(e) [curve, K1, K2, K3] = self.iso4_curve(T) if not e == 0: S = self.iso4_eval(K1, K2, K3, S, curve) if not X1 is None: X1 = self.iso4_eval(K1, K2, K3, X1, curve) if not X2 is None: X2 = self.iso4_eval(K1, K2, K3, X2, curve) if not X3 is None: X3 = self.iso4_eval(K1, K2, K3, X3, curve) return [curve, X1, X2, X3]
def isoex3(sk3, e3, pk): """ Generate shared key in 3^e3-torsion Alg. 24 from [SIKE] :param sk3: Bob's secret key :param e3: Power of 3 :param pk: Alice's public key encoded as three points :return: j-invariant of the shared curve """ curve = MontgomeryCurve(GFp2element(1)) x1 = pk[0] x2 = pk[1] x3 = pk[2] curve.seta(x1, x2, x3) s = curve.ladder3pt(sk3, x1, x2, x3) [image, _, _, _] = curve.iso3e(e3, s) return image.jinv()
def isoex2(sk2, e2, pk): """ Generate shared key in 2^e2-torsion Alg. 23 from [SIKE] :param sk2: Alice's secret key :param e2: Power of 2 :param pk: Bob's public key encoded as three points :return: j-invariant of the shared curve """ curve = MontgomeryCurve(GFp2element(1)) x1 = pk[0] x2 = pk[1] x3 = pk[2] curve.seta(x1, x2, x3) s = curve.ladder3pt(sk2, x1, x2, x3) [image, _, _, _] = curve.iso2eby4(e2, s) return image.jinv()
class MontgomeryPoint: X = GFp2element(0) Z = GFp2element(1) parent = None def getx(self): assert (not self.Z == 0) return self.X // self.Z def __init__(self, X, Z, parent): self.parent = parent assert (isinstance(X, GFp2element)) self.X = X # self.Y = Y if not Z is None: self.Z = Z else: self.Z = GFp2element(1) def __str__(self): return ('(' + str(self.X) + ' : ' + str(self.Z) + '); x = ' + str(self.X // self.Z)) def __repr__(self): return ('(' + str(self.X) + ' : ' + str(self.Z) + '); x = ' + str(self.X // self.Z)) def __add__(self, other): pass def mul2(self): """ Montgomery point x-only multiplication by 2 Alg. 3 from [SIKE] :return: """ t0 = self.X - self.Z t1 = self.X + self.Z t0 = t0 * t0 t1 = t1 * t1 z = t0 * self.parent.C24 x = z * t1 t1 = t1 - t0 t0 = t1 * self.parent.Ap24 z = z + t0 z = z * t1 return MontgomeryPoint(x, z, self.parent) def mul3(self): """ Montgomery point x-only multiplication by 3 Alg. 6 from [SIKE] :return: """ t0 = self.X - self.Z t2 = t0 * t0 t1 = self.X + self.Z t3 = t1 * t1 t4 = t1 + t0 t0 = t1 - t0 t1 = t4 * t4 t1 = t1 - t3 t1 = t1 - t2 t5 = t3 * self.parent.Ap24 t3 = t5 * t3 t6 = t2 * self.parent.Am24 t2 = t2 * t6 t3 = t2 - t3 t2 = t5 - t6 t1 = t2 * t1 t2 = t3 + t1 t2 = t2 * t2 x = t2 * t4 t1 = t3 - t1 t1 = t1 * t1 z = t1 * t0 return MontgomeryPoint(x, z, self.parent) def mul2e(self, e): """ e-repeated Montgomery point x-only multiplication by 2 Alg. 4 from [SIKE] :return: """ res = MontgomeryPoint(self.X, self.Z, self.parent) for i in range(0, e): res = res.mul2() return res def mul3e(self, e): """ e-repeated Montgomery point x-only multiplication by 3 Alg. 7 from [SIKE] :return: """ res = MontgomeryPoint(self.X, self.Z, self.parent) for i in range(0, e): res = res.mul3() return res