test = (x*xi) % p #print x, xi, x*xi, test if x != 0: assert test == 1 print('Setting up Generators') G = _curve['G'] print('ref Gen ' + str(G)) Gpt = Point(G[0],G[1]) print('Point Gen ' + str(Gpt)) GenG = Generator.init(G[0],G[1]) print('Generator Gen ' + str(GenG)) GenG2 = Generator.init(G[0],G[1]) print('Generator Gen ' + str(GenG2)) assert GenG2 is GenG assert Gpt.is_valid() assert GenG.is_valid() print('Generator uncompressed ' + str(GenG.uncompressed_format())) InfP = Point() ex = InfP.compress() exraw = InfP.uncompressed_format() InfP2 = Point.decompress(ex) InfP3 = Point.decompress(exraw) InfP4 = Point.decompress(ex.decode()) assert ex == exraw assert InfP == InfP2 assert InfP == InfP3 assert InfP == InfP4 print('Point @ Infinity') if True:
def __init__(self, nbit, b=None, u=None, G=None, friendly=True): # first, find umax, umin such that p < 2**nbit, p > 2**(nbit - 1) # p = 36u**4 + 36u**3 + 24u**2 + 6u + 1 # n = 36u**4 + 36u**3 + 18u**2 + 6u + 1 limit = pow(2, nbit) if u is None: # derive u randomly based on nbit # coarse upper, lower guesses upr = int((limit / 36)**0.25) lwr = 0 mid = (upr + lwr) >> 1 # midpoint algorithm while ((mid != upr) or (mid != lwr)): mid = (upr + lwr) >> 1 pu = _pfunc(upr) pl = _pfunc(lwr) pm = _pfunc(mid) # print("limit goal = %d" % (limit)) # print("lower p(%d) = %d" % (lwr, pl)) # print("mid p(%d) = %d" % (mid, pm)) # print("upper p(%d) = %d" % (upr, pu)) # print("") # pm should be odd, limit even. They should never meet assert (pm != limit) if pm < limit: if lwr == mid: break lwr = mid else: upr = mid umax = mid # repeat for limit = 2 ** (nbit-1) limit = pow(2, (nbit - 1)) upr = int((limit / 36)**0.25) lwr = 0 mid = (upr + lwr) >> 1 while ((mid != upr) or (mid != lwr)): mid = (upr + lwr) >> 1 pu = _pfunc(upr) pl = _pfunc(lwr) pm = _pfunc(mid) #pm should be odd, limit should be even. They should never meet assert (pm != limit) if pm < limit: if lwr == mid: break lwr = mid else: upr = mid umin = mid else: # u is a parameter umax = u umin = umax print("limit goal = %X" % (pow(2, nbit))) print("umax = %X, pmax = %X" % (umax, _pfunc(umax))) print("umin = %X, pmin = %X" % (umin, _pfunc(umin))) print("(%d potential u values, approx 2 ** %d)" % ((umax - umin) + 1, int(math.log((umax - umin) + 1, 2) + 0.5))) # choose u at random until valid solution, follow algorithm 1 from: # https://www.cryptojedi.org/papers/pfcpo.pdf self.u = 0 if u is None: while True: urand = random.randint(umin, umax) #urand = 6518589491078791937 p = _pfunc(urand) #assert p == 65000549695646603732796438742359905742825358107623003571877145026864184071783 if isPrime(p) != True: continue n = _nfunc(urand) #assert n == 65000549695646603732796438742359905742570406053903786389881062969044166799969 if isPrime(n) != True: continue if (p % 4) == 3: if ((p * p) % 16) == 9: self.u = urand self.p = p self.n = n break else: p = _pfunc(umax) n = _nfunc(umax) self.u = umax self.p = p self.n = n if b is not None: friendly = False # print("u = %X (%d)" % (self.u, self.u)) # print("p = %X (%d)" % (self.p, self.p)) # print("n = %X (%d)" % (self.n, self.n)) if friendly: # print("searching for b") while True: #select friendly parameters per Pereira et al #we happen to choose d as pure imaginary such that Xi is not c = random.randint(0, self.p) di = random.randint(0, self.p) b = pow(c, 4, self.p) - pow(di, 6, self.p) if b != (b % self.p): continue if _legendre(b + 1, self.p) != 1: continue y = _mod_sqrt(b + 1, self.p) # print("trying b = %X, y = %X, y**2 = %X" % (b, y, ((y * y) % p))) p2 = self.p * self.p # curve1 = { 'p': self.p, 'a': 0, 'b': b, 'n': self.n, 'bits': nbit } Generator.set_curve(curve1) P = Point(pow(di, 2, self.p), pow(c, 2, self.p)) assert P.is_valid() Pnm1 = (self.n - 1) * P Ptst = Pnm1 + P if Ptst.is_infinite != True: continue self.G = Generator(pow(di, 2, self.p), pow(c, 2, self.p)) self.b = b Xi = pow(c, 2, p2) + pow(di, 3, p2) bprime = (b * _modinv(Xi, p2)) h = (2 * self.p) - self.n curve2 = { 'p': self.p * self.p, 'a': 0, 'b': bprime, 'n': self.n, 'bits': 2 * nbit } break else: if G is None: if b is None: b = 0 else: b = b - 1 while True: b = b + 1 if _legendre(b + 1, self.p) != 1: # print("b = %d but %d is not quadratic residue" % (b, b+1)) continue y = _mod_sqrt(b + 1, self.p) # print("trying b = %X, y = %X, y**2 = %X" % (b, y, ((y * y) % p))) curve = { 'p': self.p, 'a': 0, 'b': b, 'n': self.n, 'bits': nbit } Generator.set_curve(curve) P = Point(1, y) assert P.is_valid() Pnm1 = (self.n - 1) * P Ptst = Pnm1 + P Pa = P.affine() if Ptst.is_infinite == True: self.G = Generator(Pa[0], Pa[1]) self.b = b break else: assert b is not None curve = { 'p': self.p, 'a': 0, 'b': b, 'n': self.n, 'bits': nbit } Generator.set_curve(curve) P = Point(G[0], G[1]) # print("P = %s" % (P.uncompressed_format())) assert P.is_valid() Pnm1 = (self.n - 1) * P Ptst = Pnm1 + P Pa = P.affine() assert Ptst.is_infinite == True self.G = Generator(Pa[0], Pa[1]) self.b = b #self.p = _pfunc(self.u) #self.n = _nfunc(self.u) print("u = %X (%d)" % (self.u, self.u)) print("p = %X (%d)" % (self.p, self.p)) print("n = %X (%d)" % (self.n, self.n)) print("b = %X (%d)" % (self.b, self.b)) print("P (compressed) = %s" % (self.G.compress())) print("P (uncompressed) = %s" % (self.G.uncompressed_format()))
# n = random.randint(0,q-1) n = i hn = iH.hashval(n) assert hn == iH2.hashval(n) ncollisions = 0 coll = [] for j in range(0, q): hc = iH.hashval(j) if (i != j) and (hc == hn): ncollisions += 1 # print("collision i, j, hash = ", i, j, hc) coll.append(j) hp = Point(infinity=True, curve=curve) if hn[1] == False: hp = Point.decompress(hn[0]) ha = hp.affine() han = (ha[0], ha[1], hp.is_infinite) if ncollisions > 0: print("n, iH(n) = ", n, han, ":", ncollisions, "collisions", coll) else: print("n, iH(n) = ", n, han) x,y = han[0], han[1] R = Point(x, y, infinity=han[2]) assert R.is_valid() Q = R + G assert Q.is_valid() rt = (pow(x, 3, q) + (a * x) + b) % q lf = pow(y, 2, q) if han[2] != True: assert rt == lf