import hashlib # for a PRNG, SHA-1 is standard and sufficiently secure def hash(seed): h = hashlib.sha1(); h.update(seed); return h.digest() seedbytes = 20 # 160-bit size for seed, determined by SHA-1 output size # 224-bit prime p produced by very similar procedure, shown in separate file p = 0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF k = GF(p); R. = k[] def secure(A,B): if k(B).is_square(): return False n = EllipticCurve([k(A),k(B)]).cardinality() return (n < p and n.is_prime() and Integers(n)(p).multiplicative_order() * 100 >= n-1) def int2str(seed,bytes): # standard big-endian encoding of integer seed return ''.join([chr((seed//256^i)%256) for i in reversed(range(bytes))]) def str2int(seed): return Integer(seed.encode('hex'),16) def update(seed): # add 1 to seed, viewed as integer return int2str(str2int(seed) + 1,len(seed)) def fullhash(seed): return str2int(hash(seed) + hash(update(seed))) % 2^223 def real2str(seed,bytes): # most significant bits of real number between 0 and 1 return int2str(Integer(floor(RealField(8*bytes+8)(seed)*256^bytes)),bytes) nums = real2str(exp(1)/16,7*seedbytes) # enough bits for all curve sizes S = nums[2*seedbytes:3*seedbytes] # previous bytes are used for 160 and 192 while True: A = fullhash(S) if not (k(A)*x^4+3).roots(): S = update(S); continue S = update(S) B = fullhash(S) if not secure(A,B): S = update(S); continue print 'p',hex(p).upper() print 'A',hex(A).upper() print 'B',hex(B).upper() break # output: # p D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF # A 2B98B906DC245F2916C03A2F953EA9AE565C3253E8AEC4BFE84C659E # B 68AEC4BFE84C659EBB8B81DC39355A2EBFA3870D98976FA2F17D2D8D