def miller_loop(Q, P): if Q is None or P is None: return FQ12.one() R = Q f_num, f_den = FQ12.one(), FQ12.one() for b in pseudo_binary_encoding[63::-1]: #for i in range(log_ate_loop_count, -1, -1): _n, _d = linefunc(R, R, P) f_num = f_num * f_num * _n f_den = f_den * f_den * _d R = double(R) #if ate_loop_count & (2**i): if b == 1: _n, _d = linefunc(R, Q, P) f_num = f_num * _n f_den = f_den * _d R = add(R, Q) elif b == -1: nQ = neg(Q) _n, _d = linefunc(R, nQ, P) f_num = f_num * _n f_den = f_den * _d R = add(R, nQ) # assert R == multiply(Q, ate_loop_count) Q1 = (Q[0]**field_modulus, Q[1]**field_modulus, Q[2]**field_modulus) # assert is_on_curve(Q1, b12) nQ2 = (Q1[0]**field_modulus, -Q1[1]**field_modulus, Q1[2]**field_modulus) # assert is_on_curve(nQ2, b12) _n1, _d1 = linefunc(R, Q1, P) R = add(R, Q1) _n2, _d2 = linefunc(R, nQ2, P) f = f_num * _n1 * _n2 / (f_den * _d1 * _d2) # R = add(R, nQ2) This line is in many specifications but it technically does nothing return f**((field_modulus**12 - 1) // curve_order)
def twist(pt): if pt is None: return None x, y = pt nx = FQ12([x.coeffs[0]] + [0] * 5 + [x.coeffs[1]] + [0] * 5) ny = FQ12([y.coeffs[0]] + [0] * 5 + [y.coeffs[1]] + [0] * 5) return (nx * w**2, ny * w**3)
def twist(pt): if pt is None: return None _x, _y, _z = pt # Field isomorphism from Z[p] / x**2 to Z[p] / x**2 - 18*x + 82 xcoeffs = [_x.coeffs[0] - _x.coeffs[1] * 9, _x.coeffs[1]] ycoeffs = [_y.coeffs[0] - _y.coeffs[1] * 9, _y.coeffs[1]] zcoeffs = [_z.coeffs[0] - _z.coeffs[1] * 9, _z.coeffs[1]] nx = FQ12([xcoeffs[0]] + [0] * 5 + [xcoeffs[1]] + [0] * 5) ny = FQ12([ycoeffs[0]] + [0] * 5 + [ycoeffs[1]] + [0] * 5) nz = FQ12([zcoeffs[0]] + [0] * 5 + [zcoeffs[1]] + [0] * 5) return (nx * w**2, ny * w**3, nz)
def twist(pt): if pt is None: return None _x, _y = pt # Field isomorphism from Z[p] / x**2 + 1 to Z[p] / x**2 - 18*x + 82 xcoeffs = [_x.coeffs[0] - _x.coeffs[1] * 9, _x.coeffs[1]] ycoeffs = [_y.coeffs[0] - _y.coeffs[1] * 9, _y.coeffs[1]] # Isomorphism into subfield of Z[p] / w**12 - 18 * w**6 + 82, # where w**6 = x nx = FQ12([xcoeffs[0]] + [0] * 5 + [xcoeffs[1]] + [0] * 5) ny = FQ12([ycoeffs[0]] + [0] * 5 + [ycoeffs[1]] + [0] * 5) # Divide x coord by w**2 and y coord by w**3 return (nx * w**2, ny * w**3)
def pairing(Q, P, final_exponentiate=True): assert is_on_curve(Q, b2) assert is_on_curve(P, b) if P[-1] == P[-1].__class__.zero() or Q[-1] == Q[-1].__class__.zero(): return FQ12.one() return miller_loop(twist(Q), cast_point_to_fq12(P), final_exponentiate=final_exponentiate)
def miller_loop(Q, P): if Q is None or P is None: return FQ12.one() R = Q f = FQ12.one() for i in range(log_ate_loop_count, -1, -1): f = f * f * linefunc(R, R, P) R = double(R) if ate_loop_count & (2**i): f = f * linefunc(R, Q, P) R = add(R, Q) # assert R == multiply(Q, ate_loop_count) Q1 = (Q[0]**field_modulus, Q[1]**field_modulus) # assert is_on_curve(Q1, b12) nQ2 = (Q1[0]**field_modulus, -Q1[1]**field_modulus) # assert is_on_curve(nQ2, b12) f = f * linefunc(R, Q1, P) R = add(R, Q1) f = f * linefunc(R, nQ2, P) # R = add(R, nQ2) This line is in many specifications but it technically does nothing return f**((field_modulus**12 - 1) // curve_order)
curve_order = 21888242871839275222246405745257275088548364400416034343698204186575808495617 NullPoint = (FQ(0), FQ(0), FQ(0)) NullPoint2 = (FQ2([0, 0]), FQ2([0, 0]), FQ2([0, 0])) # 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 G = (FQ(1), FQ(2), FQ(1)) # Generator for twisted curve over FQ2 G2 = ( FQ2([ 10857046999023057135944570762232829481370756359578518086990519993285655852781, 11559732032986387107991004021392285783925812861821192530917403151452391805634 ]), FQ2([ 8495653923123431417604973247489272438418190587263600148770280649306958101930, 4082367875863433681332203403145435568316851327593401208105741076214120093531, ]), FQ2.one(), )
def cast_point_to_fq12(pt): if pt is None: return None x, y, z = pt return (FQ12([x.n] + [0] * 11), FQ12([y.n] + [0] * 11), FQ12([z.n] + [0] * 11))