def test_many_generators(self): def all_powers(e): d = e.discriminant() e0 = e items = [] while e0 not in items: items.append(e0) self.assertEqual(e0 * e0, e0.square()) e0 *= e e0 = e0.normalized() if e0.discriminant() != d: import pdb pdb.set_trace() return items for _ in range(1000): D = -7 - _ * 8 e_id = ClassGroup.identity_for_discriminant(D) self.assertEqual(e_id, (1, 1, 2 + 2 * _)) e_id_inv = e_id.inverse() self.assertEqual(e_id, e_id_inv) e0 = ClassGroup.from_ab_discriminant(2, 1, D) e1 = e0.inverse() p0 = all_powers(e0) p1 = all_powers(e1) assert len(p0) == len(p1) assert e_id == p0[-1] assert e_id == p1[-1] for _0, _1 in zip(p0, p1): _ = _0 * _1 assert _ == e_id print("discriminant = %d; group order = %d" % (D, len(p0)))
def bench_pietrzak(): iterations = 10000 discriminant_length = 512 discriminant = create_discriminant(b"seed", discriminant_length) delta = 8 x = ClassGroup.from_ab_discriminant(2, 1, discriminant) powers_to_calculate = proof_pietrzak.cache_indeces_for_count(iterations) start_t = time.time() * time_multiplier powers = iterate_squarings(x, powers_to_calculate) vdf_time = round(time.time() * time_multiplier - start_t) y = powers[iterations] identity = ClassGroup.identity_for_discriminant(discriminant) start_t = time.time() * time_multiplier start_bench() for _ in range(5): proof = proof_pietrzak.generate_proof(x, iterations, delta, y, powers, identity, generate_r_value, discriminant_length) end_bench( "Pietrzak " + str(discriminant_length) + "b class group, " + str(iterations) + " iterations, proof", 10) proof_time = round((time.time() * time_multiplier - start_t) / 10) print(" - Percentage of VDF time:", (proof_time / vdf_time) * 100, "%") start_bench() for _ in range(10): assert (proof_pietrzak.verify_proof(x, y, proof, iterations, delta, generate_r_value, discriminant_length)) end_bench( "Pietrzak " + str(discriminant_length) + "b class group, " + str(iterations) + " iterations, verification", 10)
def test_pow(self): for _ in range(100): D = -7 - _ * 8 e_gen = ClassGroup.from_ab_discriminant(2, 1, D) p = ClassGroup.identity_for_discriminant(D) for _ in range(10): self.assertEqual(pow(e_gen, _), p) p *= e_gen
def test_inverse(self): for _ in range(1000): D = -7 - _ * 8 e_id = ClassGroup.identity_for_discriminant(D) e_gen = ClassGroup.from_ab_discriminant(2, 1, D) e_gen_inv = e_gen.inverse() e_prod = e_gen * e_gen_inv self.assertEqual(e_prod, e_id)
def bench_classgroup(): D = create_discriminant(b"seed", 512) g = ClassGroup.from_ab_discriminant(2, 1, D) while g[0].bit_length() < g[2].bit_length() or g[1].bit_length( ) < g[2].bit_length(): g = pow(g, 2) g2 = pow(g, 2) start_bench() for _ in range(0, 10000): g2 = g2.multiply(g) end_bench("Classgroup 512 bit multiply", 10000) start_bench() for _ in range(0, 10000): g2 = g2.square() end_bench("Classgroup 512 bit square", 10000) D = create_discriminant(b"seed", 1024) g = ClassGroup.from_ab_discriminant(2, 1, D) while g[0].bit_length() < g[2].bit_length() or g[1].bit_length( ) < g[2].bit_length(): g = pow(g, 2) g2 = pow(g, 2) start_bench() for _ in range(0, 10000): g2 = g2.multiply(g) end_bench("Classgroup 1024 bit multiply", 10000) start_bench() for _ in range(0, 10000): g2 = g2.square() end_bench("Classgroup 1024 bit square", 10000) D = create_discriminant(b"seed", 2048) g = ClassGroup.from_ab_discriminant(2, 1, D) while g[0].bit_length() < g[2].bit_length() or g[1].bit_length( ) < g[2].bit_length(): g = pow(g, 2) g2 = pow(g, 2) start_bench() for _ in range(0, 10000): g2 = g2.multiply(g) end_bench("Classgroup 2048 bit multiply", 10000) start_bench() for _ in range(0, 10000): g2 = g2.square() end_bench("Classgroup 2048 bit square", 10000)
def test_generator_element(self): D = -103 e_id = ClassGroup.identity_for_discriminant(D) self.assertEqual(e_id.discriminant(), D) self.assertEqual(e_id, (1, 1, 26)) e = ClassGroup.from_ab_discriminant(2, 1, D) self.assertEqual(e.discriminant(), D) self.assertEqual(e, (2, 1, 13)) e_inv = e.inverse() self.assertEqual(e_inv.discriminant(), D) self.assertEqual(e_inv, (2, -1, 13)) self.assertEqual(e * e_inv, e_id) e2 = e.square() self.assertEqual(e2, (4, -3, 7)) assert e2 == e * e e4 = e2.square() self.assertEqual(e4, (13, 1, 2)) self.assertEqual(e4, e2 * e2)
def print_entry(length): for i in range(3): seed = int.to_bytes(i, 4, 'big') d = create_discriminant(seed, length) g = ClassGroup.from_ab_discriminant(2, 1, d) order = compute_order(g) c = (1 - d) // (4 * 2) print('%s %i %i %i %i %i' % (b2a_hex(seed).decode('latin-1'), length, 2, 1, c, order))
def bench_wesolowski(): iterations = 10000 discriminant_length = 512 discriminant = create_discriminant(b"seed", discriminant_length) L, k, _ = proof_wesolowski.approximate_parameters(iterations) x = ClassGroup.from_ab_discriminant(2, 1, discriminant) powers_to_calculate = [ i * k * L for i in range(0, math.ceil(iterations / (k * L)) + 1) ] powers_to_calculate += [iterations] start_t = time.time() * time_multiplier powers = iterate_squarings(x, powers_to_calculate) vdf_time = round(time.time() * time_multiplier - start_t) y = powers[iterations] identity = ClassGroup.identity_for_discriminant(discriminant) start_t = time.time() * time_multiplier start_bench() for _ in range(5): proof = proof_wesolowski.generate_proof(identity, x, y, iterations, k, L, powers) end_bench( "Wesolowski " + str(discriminant_length) + "b class group, " + str(iterations) + " iterations, proof", 5) proof_time = round((time.time() * time_multiplier - start_t) / 5) print(" - Percentage of VDF time:", (proof_time / vdf_time) * 100, "%") start_bench() for _ in range(10): assert (proof_wesolowski.verify_proof(x, y, proof, iterations)) end_bench( "Wesolowski " + str(discriminant_length) + "b class group, " + str(iterations) + " iterations, verification", 10)
def judge_entry(mystr): assert len(mystr) < 100000 lines = mystr.strip().split(b'\n') assert len(lines) == 3 ds = set() for line in lines: # File format: # challenge(in hex) length a b c order vals = [x.strip() for x in line.strip().split(b' ')] assert len(vals) == 6 length = int(vals[1]) assert length < 5000 assert all(len(x) < length for x in vals[2:]) assert len(vals[0]) <= 32 d = create_discriminant(a2b_hex(vals[0]), length) g = ClassGroup(int(vals[2]), int(vals[3]), int(vals[4])) assert g.discriminant() == d assert g != g.identity() order = int(vals[5]) assert order > 1 assert g**order == g.identity() assert d not in ds ds.add(d) return -max(ds)
def compute_order(g: ClassGroup) -> int: d = g.discriminant() quadRoot = int((-d)**0.25) size = quadRoot order = 0 while order == 0: babylist = list( accumulate(repeat(g, quadRoot - 1), ClassGroup.multiply)) babyset = set(babylist) gSqrt = (g**quadRoot).normalized() bigStep = gSqrt result = next( filter( lambda giant: giant[1] in babyset, accumulate(repeat((1, bigStep), size), lambda old, new: (old[0] + new[0], old[1] * new[1]))), None) if result is not None: order = (result[0] * quadRoot - babylist.index(result[1]) - 1) return order size *= 2
def bench_nwesolowski(): iterations = 10000 discriminant_length = 512 discriminant = create_discriminant(b"seed", discriminant_length) L, k, _ = proof_wesolowski.approximate_parameters(iterations) x = ClassGroup.from_ab_discriminant(2, 1, discriminant) powers_to_calculate = [ i * k * L for i in range(0, math.ceil(iterations / (k * L)) + 1) ] start_t = time.time() * time_multiplier for _ in range(20): iterate_squarings(x, powers_to_calculate) vdf_time = round(time.time() * time_multiplier - start_t) / 20 start_t = time.time() * time_multiplier start_bench() for _ in range(20): result, proof = create_proof_of_time_nwesolowski(discriminant, x, iterations, discriminant_length, 2, depth=0) end_bench( "n-wesolowski depth 2 " + str(discriminant_length) + "b class group, " + str(iterations) + " iterations, proof", 20) proof_time = round((time.time() * time_multiplier - start_t) / 20) print(" - Percentage of VDF time:", (((proof_time - vdf_time) / vdf_time) * 100), "%") start_bench() for _ in range(20): assert (check_proof_of_time_nwesolowski(discriminant, x, result + proof, iterations, discriminant_length)) end_bench( "n-wesolowski depth 2 " + str(discriminant_length) + "b class group, " + str(iterations) + " iterations, verification", 20)
def classgroup_functions(): discriminant = int(''.join(textwrap.dedent(""" -277932370013051706986565094977558440925863868724962956297798375079711 1755935469152358189047817691469335967563030108724222799555095874359204 6124379271342523117944672201940224307563498623282396336043787901362415 6433157943598984236289762294443851324618151831207090436519745445815231 7564548579388388954361501155915180650886278614483121267374719433736283 5767292592316842392285011597319847853278165631070684231627247677822273 5939990747234338712430307680633635599311944191428099762576753484986313 5593175689179199446755860152120839703879033915840019194533960922418362 5935566879000287625158572127711542235803324639115306136663""").split("\n"))) discriminant = -497333706520175843802401785845247633092951073654583682148673589759912972969047267665487 initial_x = ClassGroup.from_ab_discriminant(2, 1, discriminant) # |b| <= |a| <= |c| which is approx half the bytes of the discriminant # c can be calculated from a and b, so we only need to send (a, b) element_size_bytes = discriminant.bit_length() // 8 return (initial_x, initial_x.identity(), element_size_bytes, int(discriminant.bit_length()))
def test_bad_multiply(self): n1 = ClassGroup(2243390248, -565721959, 35664920) n2 = ClassGroup(2, 1, 370) n = n1 * n2 self.assertEqual(n.discriminant(), n1.discriminant()) self.assertEqual(n.discriminant(), n2.discriminant())
def bench_vdf_iterations(): D = create_discriminant(b"seed", 512) g = ClassGroup.from_ab_discriminant(2, 1, D) start_bench() for _ in range(10): iterate_squarings(g, [10000]) end_bench("VDF 10000 iterations, 512bit classgroup", 10) D = create_discriminant(b"seed", 1024) g = ClassGroup.from_ab_discriminant(2, 1, D) start_bench() for _ in range(2): iterate_squarings(g, [10000]) end_bench("VDF 10000 iterations, 1024bit classgroup", 2) D = create_discriminant(b"seed", 2048) g = ClassGroup.from_ab_discriminant(2, 1, D) start_bench() for _ in range(2): iterate_squarings(g, [10000]) end_bench("VDF 10000 iterations, 2048bit classgroup", 2) # 2048 bit modulus prime = int(''.join( textwrap.dedent(""" 2634427397878110232503205795695468045251992992603340168049253044454387 1080897872360133472596339100961569230393163880927301060812730934043766 3646941725034559080490451986171041751558689035115943134790395616490035 9846986660803055891526943083539429058955074960014718229954545667371414 8029627597753998530121193913181474174423003742206534823264658175666814 0135440982296559552013264268674093709650866928458407571602481922443634 2306826340229149641664159565679297958087282612514993965471602016939198 7906354607787482381087158402527243744342654041944357821920600344804411 149211019651477131981627171025001255607692340155184929729""").split( "\n"))) initial_x = int_mod_n( 15619920774592561628351138998371642294622340518469892832433140464182509560910157, prime) start_bench() for _ in range(2): iterate_squarings(initial_x, [10000]) end_bench("VDF 10000 iterations, 2048bit RSA modulus", 2) # 4096 bit modulus prime = int(''.join( textwrap.dedent(""" 8466908771297228398108729385413406312941234872779790501232479567685076 4762372651919166693555570188656362906279057098994287649807661604067499 3053172889374223358861501556862285892231110003666671700028271837785598 2711897721600334848186874197010418494909265899320941516493102418008649 1453168421248338831347183727052419170386543046753155080120058844782449 2367606252473029574371603403502901208633055707823115620627698680602710 8443465519855901353485395338769455628849759950055397510380800451786140 7656499749760023191493764704430968335226478156774628814806959050849093 5035645687560103462845054697907307302184358040130405297282437884344166 7188530230135000709764482573583664708281017375197388209508666190855611 3020636147999796942848529907410787587958203267319164458728792653638371 7065019972034334447374200594285558460255762459285837794285154075321806 4811493971019446075650166775528463987738853022894781860563097254152754 1001763544907553312158598519824602240430350073539728131177239628816329 0179188493240741373702361870220590386302554494325819514615309801491107 2710093592877658471507118356670261129465668437063636041245619411937902 0658733974883998301959084381087966405508661151837877497650143949507846 1522640311670422105209760172585337397687461""").split("\n"))) initial_x = int_mod_n( 15619920774592561628351138998371642294622340518469892832433140464182509560910157, prime) start_bench() for _ in range(2): iterate_squarings(initial_x, [10000]) end_bench("VDF 10000 iterations, 4096bit RSA modulus", 2)
def find_group_order(discriminant): generator = ClassGroup.from_ab_discriminant(2, 1, d) order = compute_order(generator) return generator, order
def find_order_from_cpp(abs_disc): global correction, approx_time g = ClassGroup.from_ab_discriminant(2, 1, -abs_disc) num_baby_steps = int(abs_disc**.2 * baby_factor) num_baby_steps = min(baby_max, num_baby_steps) while True: fa = (g**(num_baby_steps * 4))[0] if miller_rabin_test(fa) and fa >= num_baby_steps: break num_baby_steps += 1 approx_time -= time.time() num_approxers = 16 max_prime = int(abs_disc**.2 * prime_factor) primes_per_process = 1 + max_prime // num_approxers primes_per_process = min(primes_per_process, max_primes_per_proc) approx_partial = [0.] * num_approxers def approx(idx): val = 1. start = idx * primes_per_process while start < max_prime: args = [ './a.out', 'approx', str(abs_disc), str(start), str(start + primes_per_process) ] # print (' '.join(args)) val *= float(subprocess.check_output(args).strip()) start += primes_per_process * num_approxers approx_partial[idx] = val threads = [ threading.Thread(target=approx, args=[x]) for x in range(num_approxers) ] for t in threads: t.start() for t in threads: t.join() # print (approx_partial) middle = (abs_disc**0.5) / 2. for v in approx_partial: middle *= v middle *= correction middle = int(middle) if middle % 2 == 1: middle += 1 num_hashes_per_giant = min(int(abs_disc**.20), 1000000) num_giants = 16 approx_time += time.time() od = find_order_parameterized(abs_disc, num_baby_steps, middle, num_hashes_per_giant, num_giants) correction_required = (correction * od) / middle correction = correction_required * learn_factor + correction * ( 1. - learn_factor) # print the true order, our approximate guess, and the updated value of correction. # Currently we manually set the initial value of this from the output back into the code. # Then for future order calculation the initial estimate is better. Can be automated. print(od, middle, correction) return od
if len(sys.argv) < 2: parser.print_help() sys.exit(0) args = parser.parse_args() with open(args.fileout, "w") as f: # first line is unused, description text f.write("bitsize:{} rstep:{} ntest:{}\n" "".format(args.bitsize, args.rstep, args.ntest)) # actual parameters for verification purposes f.write("{}\n".format(args.seed)) f.write("{}\n".format(args.rstep)) seedbytes = args.seed.encode("utf8") for i in range(args.ntest): d = create_discriminant(seedbytes + bytes([i]), args.bitsize) form = ClassGroup.from_ab_discriminant(2, 1, d) # do an initial square, equivalent to setting up the first cube form = form.square() # repeatedly apply squaring operation the requested number of times for _ in range(args.rstep): form = form.square() a, b, c = form f.write("{} {} {} {}\n".format(d, a, b, c))
def test_identity(self): for _ in range(1000): D = -7 - _ * 8 e_id = ClassGroup.identity_for_discriminant(D) e_prod = e_id * e_id self.assertEqual(e_prod, e_id)
def test_new_failure(self): t2_1_6 = ClassGroup(2, 1, 6) t4_1_3 = ClassGroup(4, 1, 3) p = t2_1_6 * t4_1_3 self.assertEqual(p, (3, 1, 4))
def test_new_failure1(self): t6_5_7 = ClassGroup(6, 5, 7) t2_1_18 = ClassGroup(2, 1, 18) p = t6_5_7 * t2_1_18 self.assertEqual(p, (4, -1, 9))
def test_paper_check(self): t12_11_3 = ClassGroup(12, 11, 3) t93_109_32 = ClassGroup(93, 109, 32) self.assertEqual(t12_11_3.discriminant(), -23) self.assertEqual(t93_109_32.discriminant(), -23) t = t12_11_3 * t93_109_32 self.assertEqual(t, ClassGroup(1, -15, 62)) self.assertEqual(t.discriminant(), -23) t1 = t93_109_32 * t12_11_3 self.assertEqual(t, t1) # the normalize and reduce example from the paper f = ClassGroup(195751, 1212121, 1876411) self.assertEqual(f.normalized(), (195751, 37615, 1807)) self.assertEqual(f.reduced(), (1, 1, 1))