def full_sieve_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) verbose = params.pop("verbose") load_matrix = params.pop("load_matrix") pre_bkz = params.pop("pre_bkz") trace = params.pop("trace") reserved_n = n params = params.new(reserved_n=reserved_n, otf_lift=False) if load_matrix is None: A, bkz = load_svpchallenge_and_randomize(n, s=0, seed=seed) if verbose: print("Loaded challenge dim %d" % n) if pre_bkz is not None: par = BKZ_FPYLLL.Param(pre_bkz, strategies=BKZ_FPYLLL.DEFAULT_STRATEGY, max_loops=1) bkz(par) else: A, _ = load_matrix_file(load_matrix, doLLL=False, high_prec=False) if verbose: print("Loaded file '%s'" % load_matrix) g6k = Siever(A, params, seed=seed) if trace: tracer = SieveTreeTracer(g6k, root_label=("full-sieve", n), start_clocks=True) else: tracer = dummy_tracer # Actually runs a workout with very large decrements, so that the basis is kind-of reduced # for the final full-sieve workout(g6k, tracer, 0, n, dim4free_min=0, dim4free_dec=15, pump_params=pump_params, verbose=verbose, **workout_params) g6k.output_bench() tracer.exit() if hasattr(tracer, "trace"): return tracer.trace else: return None
def test_bkz(): for d in dimensions: # Primal A = make_integer_matrix(d) g6k = Siever(A) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) # Dual A = make_integer_matrix(d) g6k = Siever(A) with g6k.temp_params(dual_mode=True): bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) # Primal then Dual A = make_integer_matrix(d) g6k = Siever(A) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) with g6k.temp_params(dual_mode=True): bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) # Slide A = make_integer_matrix(d) g6k = Siever(A) block_size = 25 if d == 50 else 20 slide(g6k, dummy_tracer, block_size, overlap=10) slide(g6k, dummy_tracer, block_size, overlap=10) slide(g6k, dummy_tracer, block_size, overlap=10)
def hkz_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 reserved_n = n params = params.new(reserved_n=reserved_n, otf_lift=False) verbose = params.pop("verbose") pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) verbose = params.pop("verbose") if verbose: workout_params["verbose"] = True challenge_seed = params.pop("challenge_seed") A, _ = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("hkz", n), start_clocks=True) # runs a workout woth pump-down down until the end workout(g6k, tracer, 0, n, pump_params=pump_params, verbose=verbose, **workout_params) #Just making sure pump(g6k, tracer, 15, n-15, 0, **pump_params) g6k.lll(0, n) return tracer.exit()
def test_ntru_gsa(n): # read from file filename = 'lwe_n'+str(n)+'.txt' data = open(filename, 'r').readlines() q = int(data[0]) B = eval(",".join([s_.replace('\n','').replace(" ", ", ") for s_ in data[1:n+1]])) B = IntegerMatrix.from_matrix(B) c = eval(data[n+1].replace(" ", ',')) beta, nsamples, prep_rt, GSA = find_beta(n, q, n) print('beta, nsamples:', beta, nsamples) print('GSA predicted:') print(GSA) print('beta, nsamples: ', beta, nsamples) Basis = primal_lattice_basis(B, c, q, nsamples) g6k = Siever(Basis) d = g6k.full_n g6k.lll(0, g6k.full_n) print(g6k.MatGSO) slope = basis_quality(g6k.M)["/"] print("Intial Slope = %.5f\n" % slope) print('GSA input:') print([g6k.M.get_r(i, i) for i in range(d)]) print('d:', d) target_norm = ceil( (2./3)*d + 1) + 1 print("target_norm:", target_norm) # # Preprocessing # if beta < 50: print("Starting a fpylll BKZ-%d tour. " % (beta)) sys.stdout.flush() bkz = BKZReduction(g6k.M) par = fplll_bkz.Param(beta, strategies=fplll_bkz.DEFAULT_STRATEGY, max_loops=1) bkz(par) else: print("Starting a pnjBKZ-%d tour. " % (beta)) pump_n_jump_bkz_tour(g6k, tracer, beta, jump=jump, verbose=verbose, extra_dim4free=extra_dim4free, dim4free_fun=dim4free_fun, goal_r0=target_norm, pump_params=pump_params) #T_BKZ = time.time() - T0_BKZ print('GSA output:') print([g6k.M.get_r(i, i) for i in range(d)]) return 1
def test_bkz(): for d in dimensions: # Primal A = make_integer_matrix(d) g6k = Siever(A) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) # Dual A = make_integer_matrix(d) g6k = Siever(A) with g6k.temp_params(dual_mode=True): bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) # Primal then Dual A = make_integer_matrix(d) g6k = Siever(A) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) with g6k.temp_params(dual_mode=True): bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20) bkz(g6k, dummy_tracer, 20)
def svp_kernel_trial(arg0, params=None, seed=None, goal_r0=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) dim4free_dec = params.pop("workout/dim4free_dec") pump_params = pop_prefixed_params("pump", params) challenge_seed = params.pop("challenge_seed") A, _ = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-challenge", n), start_clocks=True) gh = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(n)]) ds = list(range(0, n - 40, dim4free_dec))[::-1] + 10 * [0] if goal_r0 is None: goal_r0 = 1.1 * gh for d in ds: workout(g6k, tracer, 0, n, dim4free_dec=dim4free_dec, goal_r0=goal_r0 * 1.001, pump_params=pump_params) tracer.exit() return int(g6k.M.get_r(0, 0)), gh
def full_sieve_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 pump_params = pop_prefixed_params("pump", params) verbose = params.pop("verbose") reserved_n = n params = params.new(reserved_n=reserved_n, otf_lift=False) challenge_seed = params.pop("challenge_seed") A, _ = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("full-sieve", n), start_clocks=True) # Actually runs a workout with very large decrements, so that the basis is kind-of reduced # for the final full-sieve workout( g6k, tracer, 0, n, dim4free_min=0, dim4free_dec=15, pump_params=pump_params, verbose=verbose, ) return tracer.exit()
def asvp_kernel(arg0, params=None, seed=None): logger = logging.getLogger('asvp') # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) load_matrix = params.pop("load_matrix") pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) verbose = params.pop("verbose") if verbose: workout_params["verbose"] = True challenge_seed = params.pop("challenge_seed") if load_matrix is None: A, _ = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) if verbose: print(("Loaded challenge dim %d" % n)) else: A, _ = load_matrix_file(load_matrix) if verbose: print(("Loaded file '%s'" % load_matrix)) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-challenge", n), start_clocks=True) gh = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(n)]) goal_r0 = (1.05**2) * gh if verbose: print(("gh = %f, goal_r0/gh = %f, r0/gh = %f" % (gh, goal_r0 / gh, sum([x * x for x in A[0]]) / gh))) flast = workout(g6k, tracer, 0, n, goal_r0=goal_r0, pump_params=pump_params, **workout_params) tracer.exit() stat = tracer.trace stat.data["flast"] = flast if verbose: logger.info("sol %d, %s" % (n, A[0])) norm = sum([x * x for x in A[0]]) if verbose: logger.info("norm %.1f ,hf %.5f" % (norm**.5, (norm / gh)**.5)) return tracer.trace
def svp_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) challenge_seed = params.pop("challenge_seed") alg = params.pop("svp/alg") workout_params = pop_prefixed_params("workout/", params) pump_params = pop_prefixed_params("pump/", params) goal_r0 = 1.001 * load_svpchallenge_norm(n, s=challenge_seed) A, bkz = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-exact", n), start_clocks=True) if alg == "enum": assert len(workout_params) + len(pump_params) == 0 bkz_params = fplll_bkz.Param( block_size=n, max_loops=1, strategies=fplll_bkz.DEFAULT_STRATEGY, flags=fplll_bkz.GH_BND, ) svp_enum(bkz, bkz_params, goal_r0) flast = 0 elif alg == "duc18": assert len(workout_params) + len(pump_params) == 0 flast = ducas18(g6k, tracer, goal=goal_r0) elif alg == "workout": flast = workout(g6k, tracer, 0, n, goal_r0=goal_r0, pump_params=pump_params, **workout_params) else: raise ValueError("Unrecognized algorithm for SVP") r0 = bkz.M.get_r(0, 0) if alg == "enum" else g6k.M.get_r(0, 0) if r0 > goal_r0: raise ValueError("Did not reach the goal") if 1.002 * r0 < goal_r0: raise ValueError( "Found a vector shorter than the goal for n=%d s=%d." % (n, challenge_seed)) tracer.exit() stat = tracer.trace stat.data["flast"] = flast return stat
def plain_sieve_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 alg = params.pop("alg") reserved_n = n params = params.new(reserved_n=reserved_n, otf_lift=False) A, _ = load_svpchallenge_and_randomize(n, s=0, seed=seed) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("plain-sieve", n), start_clocks=True) g6k.initialize_local(0, 0, n) g6k(alg=alg, tracer=tracer) tracer.exit() return tracer.trace
def find_norm_kernel_trial(arg0, params=None, seed=None, goal_r0=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) dim4free_dec = params.pop("workout/dim4free_dec") pump_params = pop_prefixed_params("pump", params) load_matrix = params.pop("load_matrix") verbose = params.pop("verbose") A, _ = load_matrix_file(load_matrix, randomize=True, seed=None, float_type="double") if A.nrows != n: raise ValueError( f"wrong dimension:: Expected dim(A) = {A.nrows}, got n = {n}") g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-challenge", n), start_clocks=True) gh = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(n)]) ds = list(range(0, n - 40, dim4free_dec))[::-1] + 10 * [0] if goal_r0 is None: goal_r0 = 1.1 * gh if verbose and n < 90: verbose = False for d in ds: workout(g6k, tracer, 0, n, dim4free_dec=dim4free_dec, goal_r0=goal_r0 * 1.001, pump_params=pump_params, verbose=verbose) tracer.exit() return int(g6k.M.get_r(0, 0)), gh
def asvp_kernel(arg0, params=None, seed=None): logger = logging.getLogger('asvp') # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) load_matrix = params.pop("load_matrix") pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) verbose = params.pop("verbose") if verbose: workout_params["verbose"] = True challenge_seed = params.pop("challenge_seed") if load_matrix is None: A, _ = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) if verbose: print("Loaded challenge dim %d" % n) else: A, _ = load_matrix_file(load_matrix) if verbose: print("Loaded file '%s'" % load_matrix) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-challenge", n), start_clocks=True) gh = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(n)]) flast = workout(g6k, tracer, 0, n, pump_params=pump_params, **workout_params) tracer.exit() stat = tracer.trace f = workout_params["dim4free_min"] gh2 = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(f, n)]) quality = (gh * (n - f)) / (gh2 * n) stat.data["quality"] = quality print >> sys.stderr, g6k.M.B return tracer.trace
def asvp_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) load_matrix = params.pop("load_matrix") goal_r0__gh = params.pop('goal_r0__gh') pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) verbose = params.pop("verbose") if verbose: workout_params["verbose"] = True A, _ = load_matrix_file(load_matrix, randomize=False, seed=None, float_type="double") if verbose: print(("Loaded file '%s'" % load_matrix)) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-challenge", n), start_clocks=True) gh = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(n)]) goal_r0 = (goal_r0__gh**2) * gh if verbose: print(("gh = %f, goal_r0/gh = %f, r0/gh = %f" % (gh, goal_r0/gh, sum([x*x for x in A[0]])/gh))) flast = workout(g6k, tracer, 0, n, goal_r0=goal_r0, **workout_params) tracer.exit() stat = tracer.trace sol = tuple(A[0]) stat.data["flast"] = flast tracer.trace.data['res'] = A if verbose: print(f"svp: sol {sol}") norm = sum([x*x for x in sol]) if verbose: print("svp: norm %.1f ,hf %.5f" % (norm**.5, (norm/gh)**.5)) return tracer.trace
def bkz_kernel(arg0, params=None, seed=None): """ Run the BKZ algorithm with different parameters. :param d: the dimension of the lattices to BKZ reduce :param params: parameters for BKZ: - bkz/alg: choose the underlying BKZ from {fpylll, naive, pump_n_jump, slide} - bkz/blocksizes: given as low:high:inc perform BKZ reduction with blocksizes in range(low, high, inc) (after some light) prereduction - bkz/pre_blocksize: prereduce lattice with fpylll BKZ up to this blocksize - bkz/tours: the number of tours to do for each blocksize - bkz/extra_dim4free: lift to indices extra_dim4free earlier in the lattice than the currently sieved block - bkz/jump: the number of blocks to jump in a BKZ tour after each pump - bkz/dim4free_fun: in blocksize x, try f(x) dimensions for free, give as 'lambda x: f(x)', e.g. 'lambda x: 11.5 + 0.075*x' - pump/down_sieve: sieve after each insert in the pump-down phase of the pump - slide/overlap: shift of the dual blocks when running slide reduction - challenge_seed: a seed to randomise the generated lattice - dummy_tracer: use a dummy tracer which capture less information - verbose: print tracer information throughout BKZ run """ # Pool.map only supports a single parameter if params is None and seed is None: d, params, seed = arg0 else: d = arg0 # params for underlying BKZ/workout/pump dim4free_fun = params.pop("bkz/dim4free_fun") extra_dim4free = params.pop("bkz/extra_dim4free") jump = params.pop("bkz/jump") overlap = params.pop("slide/overlap") pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) # flow of the bkz experiment algbkz = params.pop("bkz/alg") blocksizes = params.pop("bkz/blocksizes") blocksizes = eval("range(%s)" % re.sub(":", ",", blocksizes)) pre_blocksize = params.pop("bkz/pre_blocksize") tours = params.pop("bkz/tours") # misc verbose = params.pop("verbose") dont_trace = params.pop("dummy_tracer", False) if blocksizes[-1] > d: print('set a smaller maximum blocksize with --blocksizes') return challenge_seed = params.pop("challenge_seed") A, bkz = load_prebkz(d, s=challenge_seed, blocksize=pre_blocksize) MM = GSO.Mat(A, float_type="double", U=IntegerMatrix.identity(A.nrows, int_type=A.int_type), UinvT=IntegerMatrix.identity(A.nrows, int_type=A.int_type)) g6k = Siever(MM, params, seed=seed) if dont_trace: tracer = dummy_tracer else: tracer = SieveTreeTracer(g6k, root_label=("bkz", d), start_clocks=True) if algbkz == "fpylll": M = bkz.M else: M = g6k.M T0 = time.time() for blocksize in blocksizes: for t in range(tours): with tracer.context("tour", t, dump_gso=True): if algbkz == "fpylll": par = BKZ_FPYLLL.Param( blocksize, strategies=BKZ_FPYLLL.DEFAULT_STRATEGY, max_loops=1) bkz(par) elif algbkz == "naive": naive_bkz_tour(g6k, tracer, blocksize, extra_dim4free=extra_dim4free, dim4free_fun=dim4free_fun, workout_params=workout_params, pump_params=pump_params) elif algbkz == "pump_and_jump": pump_n_jump_bkz_tour(g6k, tracer, blocksize, jump=jump, dim4free_fun=dim4free_fun, extra_dim4free=extra_dim4free, pump_params=pump_params) elif algbkz == "slide": slide_tour(g6k, dummy_tracer, blocksize, overlap=overlap, dim4free_fun=dim4free_fun, extra_dim4free=extra_dim4free, workout_params=workout_params, pump_params=pump_params) else: raise ValueError("bkz/alg=%s not recognized." % algbkz) if verbose: slope = basis_quality(M)["/"] fmt = "{'alg': '%25s', 'jump':%2d, 'pds':%d, 'extra_d4f': %2d, 'beta': %2d, 'slope': %.5f, 'total walltime': %.3f}" # noqa print(fmt % (algbkz + "+" + ("enum" if algbkz == "fpylll" else g6k.params.default_sieve), jump, pump_params["down_sieve"], extra_dim4free, blocksize, slope, time.time() - T0)) tracer.exit() slope = basis_quality(M)["/"] stat = tracer.trace try: stat.data["slope"] = np.array(slope) return stat except AttributeError: return None
def run(self): self.thread_name = current_thread().name if self.thread_name == "MainThread": self.thread_name = " " self.thread_start = time.time() self.tried = set() dim = self.params["dimension"] if self.params["bounds"]["type"] in ("known", "knownre"): sigs = self.signatures self.signatures = [] blens = [] for sig in sigs: blen = int(self.recompute_nonce(sig)).bit_length() i = bisect(blens, blen) if i < dim: blens.insert(i, blen) self.signatures.insert(i, sig) if len(blens) > dim: blens.pop() self.signatures.pop() pairs = [(sig.t, sig.u) for sig in self.signatures[:dim]] nonces = [] for sig in self.signatures[:dim]: nonces.append(int(self.recompute_nonce(sig))) real_bitlens = [nonce.bit_length() for nonce in nonces] real_infos = [ self.curve.group.n.bit_length() - bitlen for bitlen in real_bitlens ] real_info = sum(real_infos) if self.params["bounds"]["type"] == "constant": value = self.const_bound_func(self.params["bounds"]) self.bounds = [value for _ in range(dim)] elif self.params["bounds"]["type"] == "geom": self.bounds = [ self.geom_bound_func(i, dim, self.params["bounds"]) for i in range(dim) ] elif self.params["bounds"]["type"] == "geomN": self.bounds = [ self.geomN_bound_func(i, self.params["attack"]["num"], self.params["bounds"]) for i in range(dim) ] elif self.params["bounds"]["type"] == "known" or self.params["bounds"][ "type"] == "knownre": self.bounds = [self.known_bound_func(i, dim) for i in range(dim)] elif self.params["bounds"]["type"] == "template": self.bounds = [0 for _ in range(dim)] templates = copy(self.params["bounds"]) del templates["type"] for k, v in templates.items(): for i in range(*v): self.bounds[i] = self.curve.group.n.bit_length() - int(k) bnds = [self.bounds[i] for i in range(dim)] info = sum(bnds) overhead = info / self.curve.bit_size() self.log( "Building lattice with {} bits of information (overhead {:.2f}).". format(info, overhead)) liars = 0 bad_info = 0 good_info = 0 liarpos = [] for i, real, our in zip(range(dim), real_infos, bnds): if real < our: liars += 1 bad_info += real liarpos.append(str(i) + "@" + str(our - real)) else: good_info += real self.log("Real info: {}".format(real_info)) self.log("Liars: {}".format(liars)) self.log("Good info: {}".format(good_info)) self.log("Bad info: {}".format(bad_info)) self.log("Liar positions: {}".format(";".join(liarpos))) self.svp = self.params["attack"]["method"] == "svp" self.sieve = self.params["attack"]["method"] == "sieve" self.np = self.params["attack"]["method"] == "np" self.round = self.params["attack"]["method"] == "round" if self.svp or self.sieve: lattice = self.build_svp_lattice(pairs, dim, self.params["bounds"]) elif self.np or self.round: lattice = self.build_cvp_lattice(pairs, dim, self.params["bounds"]) target = self.build_target(pairs, dim, self.params["bounds"]) else: self.log("Bad method: {}".format(self.params["attack"]["method"])) return if self.sieve: self.reduce_lattice(lattice, None) g6k = Siever(lattice) self.log("Start SIEVE.") g6k.initialize_local(0, 0, dim) try: g6k() except SaturationError as e: pass short = self.verify_sieve(lattice, g6k.best_lifts()) if short is not None: i, res = short self.log("Result row: {}".format(i)) norm = self.norm(res) self.log("Result normdist: {}".format(norm)) return reds = [None] + self.params["betas"] for beta in reds: lattice = self.reduce_lattice(lattice, beta) gso = GSO.Mat(lattice) gso.update_gso() if self.svp: short = self.verify_shortest(lattice, self.pubkey) if short is not None: i, res = short self.log("Result row: {}".format(i)) norm = self.norm(res) self.log("Result normdist: {}".format(norm)) break if self.round: closest = self.babai_round(lattice, target) if self.verify_closest(closest, self.pubkey): dist = self.dist(closest, target) self.log("Result normdist: {}".format(dist)) break if self.np: closest = self.babai_np(lattice, gso, target) if self.verify_closest(closest, self.pubkey) is not None: dist = self.dist(closest, target) self.log("Result normdist: {}".format(dist)) break
def asvp_kernel(arg0, params=None, seed=None): logger = logging.getLogger('asvp') # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) load_matrix = params.pop("load_matrix") pre_bkz = params.pop("pre_bkz") pump_params = pop_prefixed_params("pump", params) workout_params = pop_prefixed_params("workout", params) verbose = params.pop("verbose") if verbose: workout_params["verbose"] = True challenge_seed = params.pop("challenge_seed") high_prec = params.pop("high_prec") trace = params.pop("trace") if load_matrix is None: A, bkz = load_svpchallenge_and_randomize(n, s=challenge_seed, seed=seed) if verbose: print("Loaded challenge dim %d" % n) if pre_bkz is not None: par = BKZ_FPYLLL.Param(pre_bkz, strategies=BKZ_FPYLLL.DEFAULT_STRATEGY, max_loops=1) bkz(par) else: A, _ = load_matrix_file(load_matrix, doLLL=False, high_prec=high_prec) if verbose: print("Loaded file '%s'" % load_matrix) g6k = Siever(A, params, seed=seed) if trace: tracer = SieveTreeTracer(g6k, root_label=("svp-challenge", n), start_clocks=True) else: tracer = dummy_tracer gh = gaussian_heuristic([g6k.M.get_r(i, i) for i in range(n)]) gamma = params.pop("gamma") if gamma is None: goal_r0 = (1.05**2) * gh else: goal_r0 = gamma**2 * gh if verbose: print("gh = %f, goal_r0/gh = %f, r0/gh = %f" % (gh, goal_r0 / gh, sum([x * x for x in A[0]]) / gh)) flast = workout(g6k, tracer, 0, n, goal_r0=goal_r0, pump_params=pump_params, **workout_params) if verbose: logger.info("sol %d, %s" % (n, A[0])) norm = sum([x * x for x in A[0]]) if verbose: logger.info("norm %.1f ,hf %.5f" % (norm**.5, (norm / gh)**.5)) tracer.exit() if hasattr(tracer, "trace"): stat = tracer.trace stat.data["flast"] = flast return stat else: return None
def svp_kernel(arg0, params=None, seed=None): # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) load_matrix = params.pop("load_matrix") alg = params.pop("svp/alg") goal_r0 = 1.001 * params.pop('goal_r0') workout_params = pop_prefixed_params("workout/", params) pump_params = pop_prefixed_params("pump/", params) verbose = params.pop("verbose") if verbose and alg == "workout": workout_params["verbose"] = True A, bkz = load_matrix_file(load_matrix, randomize=True, seed=seed, float_type="double") if verbose: print(("Loaded file '%s'" % load_matrix)) g6k = Siever(A, params, seed=seed) tracer = SieveTreeTracer(g6k, root_label=("svp-exact", n), start_clocks=True) if alg == "enum": assert len(workout_params) + len(pump_params) == 0 bkz_params = fplll_bkz.Param(block_size=n, max_loops=1, strategies=fplll_bkz.DEFAULT_STRATEGY, flags=fplll_bkz.GH_BND) svp_enum(bkz, bkz_params, goal_r0) flast = -1 elif alg == "duc18": assert len(workout_params) + len(pump_params) == 0 flast = ducas18(g6k, tracer, goal=goal_r0) elif alg == "workout": flast = workout(g6k, tracer, 0, n, goal_r0=goal_r0, pump_params=pump_params, **workout_params) else: raise ValueError("Unrecognized algorithm for SVP") r0 = bkz.M.get_r(0, 0) if alg == "enum" else g6k.M.get_r(0, 0) if r0 > goal_r0: raise ValueError('Did not reach the goal') if 1.002 * r0 < goal_r0: raise ValueError( 'Found a vector(%d) shorter than the goal(%d) for n=%d.' % (r0, goal_r0, n)) if verbose: print("sol %d, %s" % (n, A[0])) tracer.exit() stat = tracer.trace stat.data["flast"] = flast tracer.trace.data['res'] = A return stat
def lwe_kernel(arg0, params=None, seed=None): """ Run the primal attack against Darmstadt LWE instance (n, alpha). :param n: the dimension of the LWE-challenge secret :param params: parameters for LWE: - lwe/alpha: the noise rate of the LWE-challenge - lwe/m: the number of samples to use for the primal attack - lwe/goal_margin: accept anything that is goal_margin * estimate(length of embedded vector) as an lwe solution - lwe/svp_bkz_time_factor: if > 0, run a larger pump when svp_bkz_time_factor * time(BKZ tours so far) is expected to be enough time to find a solution - bkz/blocksizes: given as low:high:inc perform BKZ reduction with blocksizes in range(low, high, inc) (after some light) prereduction - bkz/tours: the number of tours to do for each blocksize - bkz/jump: the number of blocks to jump in a BKZ tour after each pump - bkz/extra_dim4free: lift to indices extra_dim4free earlier in the lattice than the currently sieved block - bkz/fpylll_crossover: use enumeration based BKZ from fpylll below this blocksize - bkz/dim4free_fun: in blocksize x, try f(x) dimensions for free, give as 'lambda x: f(x)', e.g. 'lambda x: 11.5 + 0.075*x' - pump/down_sieve: sieve after each insert in the pump-down phase of the pump - dummy_tracer: use a dummy tracer which captures less information - verbose: print information throughout the lwe challenge attempt """ # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) # params for underlying BKZ extra_dim4free = params.pop("bkz/extra_dim4free") jump = params.pop("bkz/jump") dim4free_fun = params.pop("bkz/dim4free_fun") pump_params = pop_prefixed_params("pump", params) fpylll_crossover = params.pop("bkz/fpylll_crossover") blocksizes = params.pop("bkz/blocksizes") tours = params.pop("bkz/tours") # flow of the lwe solver svp_bkz_time_factor = params.pop("lwe/svp_bkz_time_factor") goal_margin = params.pop("lwe/goal_margin") # generation of lwe instance and Kannan's embedding alpha = params.pop("lwe/alpha") m = params.pop("lwe/m") decouple = svp_bkz_time_factor > 0 # misc dont_trace = params.pop("dummy_tracer") verbose = params.pop("verbose") A, c, q = load_lwe_challenge(n=n, alpha=alpha) print "-------------------------" print "Primal attack, LWE challenge n=%d, alpha=%.4f" % (n, alpha) if m is None: try: min_cost_param = gsa_params(n=A.ncols, alpha=alpha, q=q, samples=A.nrows, decouple=decouple) (b, s, m) = min_cost_param except TypeError: raise TypeError("No winning parameters.") else: try: min_cost_param = gsa_params(n=A.ncols, alpha=alpha, q=q, samples=m, decouple=decouple) (b, s, _) = min_cost_param except TypeError: raise TypeError("No winning parameters.") print "Chose %d samples. Predict solution at bkz-%d + svp-%d" % (m, b, s) print target_norm = goal_margin * (alpha*q)**2 * m + 1 if blocksizes is not None: blocksizes = range(10, 40) + eval("range(%s)" % re.sub(":", ",", blocksizes)) # noqa else: blocksizes = range(10, 50) + [b-20, b-17] + range(b - 14, b + 25, 2) B = primal_lattice_basis(A, c, q, m=m) g6k = Siever(B, params) print "GSO precision: ", g6k.M.float_type if dont_trace: tracer = dummy_tracer else: tracer = SieveTreeTracer(g6k, root_label=("lwe"), start_clocks=True) d = g6k.full_n g6k.lll(0, g6k.full_n) slope = basis_quality(g6k.M)["/"] print "Intial Slope = %.5f\n" % slope T0 = time.time() T0_BKZ = time.time() for blocksize in blocksizes: for tt in range(tours): # BKZ tours if blocksize < fpylll_crossover: if verbose: print "Starting a fpylll BKZ-%d tour. " % (blocksize), sys.stdout.flush() bkz = BKZReduction(g6k.M) par = fplll_bkz.Param(blocksize, strategies=fplll_bkz.DEFAULT_STRATEGY, max_loops=1) bkz(par) else: if verbose: print "Starting a pnjBKZ-%d tour. " % (blocksize) pump_n_jump_bkz_tour(g6k, tracer, blocksize, jump=jump, verbose=verbose, extra_dim4free=extra_dim4free, dim4free_fun=dim4free_fun, goal_r0=target_norm, pump_params=pump_params) T_BKZ = time.time() - T0_BKZ if verbose: slope = basis_quality(g6k.M)["/"] fmt = "slope: %.5f, walltime: %.3f sec" print fmt % (slope, time.time() - T0) g6k.lll(0, g6k.full_n) if g6k.M.get_r(0, 0) <= target_norm: break # overdoing n_max would allocate too much memory, so we are careful svp_Tmax = svp_bkz_time_factor * T_BKZ n_max = int(58 + 2.85 * log(svp_Tmax * params.threads)/log(2.)) rr = [g6k.M.get_r(i, i) for i in range(d)] for n_expected in range(2, d-2): x = (target_norm/goal_margin) * n_expected/(1.*d) if 4./3 * gaussian_heuristic(rr[d-n_expected:]) > x: break print "Without otf, would expect solution at pump-%d. n_max=%d in the given time." % (n_expected, n_max) # noqa if n_expected >= n_max - 1: continue n_max += 1 # Larger SVP llb = d - blocksize while gaussian_heuristic([g6k.M.get_r(i, i) for i in range(llb, d)]) < target_norm * (d - llb)/(1.*d): # noqa llb -= 1 f = d-llb-n_max if verbose: print "Starting svp pump_{%d, %d, %d}, n_max = %d, Tmax= %.2f sec" % (llb, d-llb, f, n_max, svp_Tmax) # noqa pump(g6k, tracer, llb, d-llb, f, verbose=verbose, goal_r0=target_norm * (d - llb)/(1.*d)) if verbose: slope = basis_quality(g6k.M)["/"] fmt = "\n slope: %.5f, walltime: %.3f sec" print fmt % (slope, time.time() - T0) print g6k.lll(0, g6k.full_n) T0_BKZ = time.time() if g6k.M.get_r(0, 0) <= target_norm: break if g6k.M.get_r(0, 0) <= target_norm: print "Finished! TT=%.2f sec" % (time.time() - T0) print g6k.M.B[0] alpha_ = int(alpha*1000) filename = 'lwechallenge/%03d-%03d-solution.txt' % (n, alpha_) fn = open(filename, "w") fn.write(str(g6k.M.B[0])) fn.close() return raise ValueError("No solution found.")
def ntru_kernel(arg0, params=None, seed=None): """ Run the primal attack against Darmstadt LWE instance (n, alpha). :param n: the dimension of the LWE-challenge secret :param params: parameters for LWE: - lwe/alpha: the noise rate of the LWE-challenge - lwe/m: the number of samples to use for the primal attack - lwe/goal_margin: accept anything that is goal_margin * estimate(length of embedded vector) as an lwe solution - lwe/svp_bkz_time_factor: if > 0, run a larger pump when svp_bkz_time_factor * time(BKZ tours so far) is expected to be enough time to find a solution - bkz/blocksizes: given as low:high:inc perform BKZ reduction with blocksizes in range(low, high, inc) (after some light) prereduction - bkz/tours: the number of tours to do for each blocksize - bkz/jump: the number of blocks to jump in a BKZ tour after each pump - bkz/extra_dim4free: lift to indices extra_dim4free earlier in the lattice than the currently sieved block - bkz/fpylll_crossover: use enumeration based BKZ from fpylll below this blocksize - bkz/dim4free_fun: in blocksize x, try f(x) dimensions for free, give as 'lambda x: f(x)', e.g. 'lambda x: 11.5 + 0.075*x' - pump/down_sieve: sieve after each insert in the pump-down phase of the pump - dummy_tracer: use a dummy tracer which captures less information - verbose: print information throughout the lwe challenge attempt """ # Pool.map only supports a single parameter if params is None and seed is None: n, params, seed = arg0 else: n = arg0 params = copy.copy(params) # params for underlying BKZ extra_dim4free = params.pop("bkz/extra_dim4free") jump = params.pop("bkz/jump") dim4free_fun = params.pop("bkz/dim4free_fun") pump_params = pop_prefixed_params("pump", params) fpylll_crossover = params.pop("bkz/fpylll_crossover") blocksizes = params.pop("bkz/blocksizes") tours = params.pop("bkz/tours") # flow of the lwe solver svp_bkz_time_factor = params.pop("lwe/svp_bkz_time_factor") goal_margin = params.pop("lwe/goal_margin") # generation of lwe instance and Kannan's embedding alpha = params.pop("lwe/alpha") m = params.pop("lwe/m") decouple = svp_bkz_time_factor > 0 # misc dont_trace = params.pop("dummy_tracer") verbose = params.pop("verbose") filename = 'ntru_n_'+str(n)+'.txt' H, q = read_ntru_from_file(filename) print("-------------------------") print("Hybrid attack on NTRU n=%d" %n) # compute the attack parameters paramset_NTRU1 = {'n': n, 'q': q, 'w': 2*(n/3)} print(paramset_NTRU1) beta, g, rt = plain_hybrid_compleixty(paramset_NTRU1, verbose = True) B = ntru_plain_hybrid_basis(A, g, q, m=m) g6k = Siever(B, params) print("GSO precision: ", g6k.M.float_type) if dont_trace: tracer = dummy_tracer else: tracer = SieveTreeTracer(g6k, root_label=("ntru"), start_clocks=True) d = g6k.full_n g6k.lll(0, g6k.full_n) slope = basis_quality(g6k.M)["/"] print("Intial Slope = %.5f\n" % slope) T0 = time.time() T0_BKZ = time.time() for blocksize in blocksizes: for tt in range(tours): # BKZ tours if blocksize < fpylll_crossover: if verbose: print("Starting a fpylll BKZ-%d tour. " % (blocksize), end=' ') sys.stdout.flush() bkz = BKZReduction(g6k.M) par = fplll_bkz.Param(blocksize, strategies=fplll_bkz.DEFAULT_STRATEGY, max_loops=1) bkz(par) else: if verbose: print("Starting a pnjBKZ-%d tour. " % (blocksize)) pump_n_jump_bkz_tour(g6k, tracer, blocksize, jump=jump, verbose=verbose, extra_dim4free=extra_dim4free, dim4free_fun=dim4free_fun, goal_r0=target_norm, pump_params=pump_params) T_BKZ = time.time() - T0_BKZ if verbose: slope = basis_quality(g6k.M)["/"] fmt = "slope: %.5f, walltime: %.3f sec" print(fmt % (slope, time.time() - T0)) g6k.lll(0, g6k.full_n) if g6k.M.get_r(0, 0) <= target_norm: break # overdoing n_max would allocate too much memory, so we are careful svp_Tmax = svp_bkz_time_factor * T_BKZ n_max = int(58 + 2.85 * log(svp_Tmax * params.threads)/log(2.)) rr = [g6k.M.get_r(i, i) for i in range(d)] for n_expected in range(2, d-2): x = (target_norm/goal_margin) * n_expected/(1.*d) if 4./3 * gaussian_heuristic(rr[d-n_expected:]) > x: break print("Without otf, would expect solution at pump-%d. n_max=%d in the given time." % (n_expected, n_max)) # noqa if n_expected >= n_max - 1: continue n_max += 1 # Larger SVP llb = d - blocksize while gaussian_heuristic([g6k.M.get_r(i, i) for i in range(llb, d)]) < target_norm * (d - llb)/(1.*d): # noqa llb -= 1 f = d-llb-n_max if verbose: print("Starting svp pump_{%d, %d, %d}, n_max = %d, Tmax= %.2f sec" % (llb, d-llb, f, n_max, svp_Tmax)) # noqa pump(g6k, tracer, llb, d-llb, f, verbose=verbose, goal_r0=target_norm * (d - llb)/(1.*d)) if verbose: slope = basis_quality(g6k.M)["/"] fmt = "\n slope: %.5f, walltime: %.3f sec" print(fmt % (slope, time.time() - T0)) print() g6k.lll(0, g6k.full_n) T0_BKZ = time.time() if g6k.M.get_r(0, 0) <= target_norm: break if g6k.M.get_r(0, 0) <= target_norm: print("Finished! TT=%.2f sec" % (time.time() - T0)) print(g6k.M.B[0]) alpha_ = int(alpha*1000) filename = 'lwechallenge/%03d-%03d-solution.txt' % (n, alpha_) fn = open(filename, "w") fn.write(str(g6k.M.B[0])) fn.close() return """ raise ValueError("No solution found.") def ntru(): """ Attempt to solve an ntru instance. """ description = ntru.__doc__ args, all_params = parse_args(description, ntru__m=None, lwe__goal_margin=1.5, lwe__svp_bkz_time_factor=1, bkz__blocksizes=None, bkz__tours=1, bkz__jump=1, bkz__extra_dim4free=12, bkz__fpylll_crossover=51, bkz__dim4free_fun="default_dim4free_fun", pump__down_sieve=True, dummy_tracer=True, # set to control memory verbose=True ) stats = run_all(ntru_kernel, list(all_params.values()), # noqa lower_bound=args.lower_bound, upper_bound=args.upper_bound, step_size=args.step_size, trials=args.trials, workers=args.workers, seed=args.seed)
def test_bkz(): for d in dimensions: A = make_integer_matrix(d) g6k = Siever(A) bkz(g6k, dummy_tracer, 20)