def worker_process(seed, params, queue=None): """ This function is called to collect statistics. :param A: basis :param params: BKZ parameters :param queue: queue used for communication """ FPLLL.set_random_seed(seed) A = IntegerMatrix.random(params.block_size, "qary", bits=30, k=params.block_size//2, int_type="long") M = GSO.Mat(A) bkz = CallbackBKZ(M) # suppresses initial LLL call tracer = BKZTreeTracer(bkz, start_clocks=True) with tracer.context(("tour", 0)): bkz.svp_reduction(0, params.block_size, params, tracer) M.update_gso() tracer.exit() try: # close connection params.strategies[params.block_size].connection.send(None) except AttributeError: pass if queue: queue.put(tracer.trace) else: return tracer.trace
def worker_process(seed, params, queue=None): """ This function is called to collect statistics. :param A: basis :param params: BKZ parameters :param queue: queue used for communication """ FPLLL.set_random_seed(seed) A = IntegerMatrix.random(params.block_size, "qary", bits=30, k=params.block_size // 2, int_type="long") M = GSO.Mat(A) bkz = CallbackBKZ(M) # suppresses initial LLL call tracer = BKZTreeTracer(bkz, start_clocks=True) with tracer.context(("tour", 0)): bkz.svp_reduction(0, params.block_size, params, tracer) M.update_gso() tracer.exit() try: # close connection params.strategies[params.block_size].connection.send(None) except AttributeError: pass if queue: queue.put(tracer.trace) else: return tracer.trace
def svp_time(seed, params, return_queue=None): """Run SVP reduction of AutoBKZ on ``A`` using ``params``. :param A: a matrix :param params: AutoBKZ parameters :param queue: if not ``None``, the result is put on this queue. """ FPLLL.set_random_seed(seed) FPLLL.set_threads(params["threads"]) q = 33554393 k = params.block_size // 2 A = IntegerMatrix.random(params.block_size, "qary", q=q, k=k, int_type="long") M = GSO.Mat(A) bkz = BKZ2(M) tracer = BKZTreeTracer(bkz, start_clocks=True) with tracer.context(("tour", 0)): bkz.svp_reduction(0, params.block_size, params, tracer) bkz.M.update_gso() tracer.exit() log_delta = (log(A[0].norm()) - log(q) * (k / float(params.block_size))) / float(params.block_size) tracer.trace.data["delta"] = exp(log_delta) if return_queue: return_queue.put(tracer.trace) else: return tracer.trace
def __call__(self, params, min_row=0, max_row=-1): """Run the BKZ algorithm with parameters `param`. :param params: BKZ parameters :param min_row: start processing in this row :param max_row: stop processing in this row (exclusive) """ tracer = BKZTreeTracer(self, verbosity=params.flags & BKZ.VERBOSE, start_clocks=True) if params.flags & BKZ.AUTO_ABORT: auto_abort = BKZ.AutoAbort(self.M, self.A.nrows) cputime_start = time.clock() with tracer.context("lll"): self.lll_obj() i = 0 while True: with tracer.context("tour", i): clean = self.tour(params, min_row, max_row, tracer) i += 1 if clean or params.block_size >= self.A.nrows: break if (params.flags & BKZ.AUTO_ABORT) and auto_abort.test_abort(): break if (params.flags & BKZ.MAX_LOOPS) and i >= params.max_loops: break if (params.flags & BKZ.MAX_TIME) and time.clock() - cputime_start >= params.max_time: break tracer.exit() self.trace = tracer.trace return clean
def osvp_time(seed, params, return_queue=None): """Run oSVP reduction on ``A`` using ``params``. :param seed: random seed for matrix creation :param params: BKZ parameters :param return_queue: if not ``None``, the result is put on this queue. """ from cost import sample_matrix A = sample_matrix(ceil(params.block_size * (1 + params["c"])), seed=seed) M = GSO.Mat(A) bkz = OBKZ(M, c=params["c"]) tracer = BKZTreeTracer(bkz, start_clocks=True) with tracer.context(("tour", 0)): bkz.svp_reduction(0, params.block_size, params, tracer) bkz.M.update_gso() tracer.exit() tracer.trace.data["|A_0|"] = A[0].norm() ppbs = params.strategies[params.block_size].preprocessing_block_sizes tracer.trace.data["preprocessing_block_size"] = ppbs[0] if ppbs else 2 if return_queue: return_queue.put(tracer.trace) else: return tracer.trace
def svp_time(seed, params, return_queue=None): """Run SVP reduction of AutoBKZ on ``A`` using ``params``. :param A: a matrix :param params: AutoBKZ parameters :param queue: if not ``None``, the result is put on this queue. """ FPLLL.set_random_seed(seed) A = IntegerMatrix.random(params.block_size, "qary", bits=30, k=params.block_size//2, int_type="long") M = GSO.Mat(A) bkz = BKZ2(M) tracer = BKZTreeTracer(bkz, start_clocks=True) with tracer.context(("tour", 0)): bkz.svp_reduction(0, params.block_size, params, tracer) bkz.M.update_gso() tracer.exit() tracer.trace.data["|A_0|"] = A[0].norm() if return_queue: return_queue.put(tracer.trace) else: return tracer.trace
def __call__(cls, M, predicate, block_size, invalidate_cache=lambda: None, max_loops=8, threads=1, **kwds): bkz = BKZ2(M) if block_size > STRATEGIES_MAX_DIM: warnings.warn( "reducing block size to {max}".format(max=STRATEGIES_MAX_DIM)) block_size = STRATEGIES_MAX_DIM FPLLL.set_threads(threads) params = BKZ.EasyParam(block_size=block_size, **kwds) auto_abort = BKZ.AutoAbort(M, M.d) tracer = BKZTreeTracer(bkz, root_label="bkz_enum", start_clocks=True) found, ntests, solution = False, 0, None for tour in range(max_loops): bkz.tour(params) if auto_abort.test_abort(): break invalidate_cache() with tracer.context("check"): for i, v in enumerate(bkz.M.B): ntests += 1 if predicate(v, standard_basis=True): found = True solution = tuple([int(v_) for v_ in v]) break if found: break FPLLL.set_threads(1) tracer.exit() b0, b0e = bkz.M.get_r_exp(0, 0) return USVPPredSolverResults( success=found, solution=solution, ntests=ntests, b0=b0**(0.5) * 2**(b0e / 2.0), cputime=tracer.trace.data["cputime"], walltime=tracer.trace.data["walltime"], data=tracer.trace, )
def play(BKZ, A, block_size, tours, progressive_step_size=None): """Call ``BKZ`` on ``A`` with ``block_size`` for the given number of ``tours``. The given number of tours is used for all block sizes from 2 up to ``block_size`` in increments of ``progressive_step_size``. Providing ``None`` for this parameter disables the progressive strategy. :param BKZ: a BKZ class whose ``__call__`` accepts a single block size as parameter :param A: an integer matrix :param block_size: a block size >= 2 :param tours: number of tours >= 1 :param progressive_step_size: step size for progressive strategy :returns: a trace of the execution using ``BKZTreeTracer`` .. note :: This function essentially reimplements ``BKZ.__call__`` but supports the progressive strategy. """ bkz = BKZ(copy.copy(A)) tracer = BKZTreeTracer(bkz, start_clocks=True) # this essentially initialises the GSO object, LLL was already run by the constructor, so this # is quick. with tracer.context("lll"): bkz.lll_obj() if progressive_step_size is None: block_sizes = (block_size, ) elif int(progressive_step_size) > 0: block_sizes = range(2, block_size + 1, progressive_step_size) if block_sizes[-1] != block_size: block_sizes.append(block_size) else: raise ValueError("Progressive step size of %s not understood." % progressive_step_size) for block_size in block_sizes: for i in range(tours): with tracer.context("tour", (block_size, i)): bkz.tour(block_size, tracer=tracer) tracer.exit() trace = tracer.trace quality = basis_quality(bkz.M) for k, v in quality.items(): trace.data[k] = v return trace
def bkz_call(BKZ, A, block_size, tours, progressive_step_size=None): """Call ``BKZ`` on ``A`` with ``block_size`` for the given number of ``tours``. If ``return_queue`` is not ``None`` then the trace and the provided ``tag`` are put on the queue. Otherwise, they are returned. :param BKZ: :param A: :param block_size: :param tours: :param progressive_step_size: .. note :: This function essentially reimplements ``BKZ.__call__`` but supports the progressive strategy. """ bkz = BKZ(copy.copy(A)) tracer = BKZTreeTracer(bkz, start_clocks=True) # this essentially initialises the GSO object, LLL was already run by the constructor, so this # is quick. with tracer.context("lll"): bkz.lll_obj() if progressive_step_size is None: block_sizes = (block_size, ) elif int(progressive_step_size) > 0: block_sizes = range(2, block_size + 1, progressive_step_size) if block_sizes[-1] != block_size: block_sizes.append(block_size) else: raise ValueError("Progressive step size of %s not understood." % progressive_step_size) for block_size in block_sizes: for i in range(tours): with tracer.context("tour", (block_size, i)): bkz.tour(block_size, tracer=tracer) tracer.exit() trace = tracer.trace quality = basis_quality(bkz.M) for k, v in quality.items(): trace.data[k] = v return trace
def __call__(cls, M, predicate, squared_target_norm, invalidate_cache=lambda: None, target_prob=None, preproc_offset=20, ph=0, threads=1, **kwds): preproc_time = None ntests = 0 if target_prob is None: target_prob = cls.DEFAULT_TARGET_PROB bkz_res = usvp_pred_bkz_enum_solve(M, predicate, block_size=min( STRATEGIES_MAX_DIM, M.d), invalidate_cache=invalidate_cache, threads=threads) if bkz_res.success: # this might be enough return bkz_res FPLLL.set_threads(threads) M.update_gso() bkz = BKZ2(M) tracer = BKZTreeTracer(bkz, root_label="enum_pred", start_clocks=True) remaining_probability, rerandomize, found, solution = (1.0, False, False, None) while remaining_probability > 1.0 - target_prob: invalidate_cache() with tracer.context("preprocessing"): if rerandomize: with tracer.context("randomization"): bkz.randomize_block(0, M.d, tracer=tracer, density=3) with tracer.context("reduction"): with tracer.context("lll"): bkz.lll_obj() for _ in range(4): bkz.tour( BKZ.EasyParam(min(max(M.d - preproc_offset, 2), STRATEGIES_MAX_DIM), flags=BKZ.GH_BND), tracer=tracer, ) if preproc_time is None: preproc_time = float( tracer.trace.child("preprocessing")["cputime"]) with tracer.context("check"): for v in M.B: ntests += 1 if predicate(v, standard_basis=True): found = True solution = tuple([int(v_) for v_ in v]) break if found: break with tracer.context("pruner"): preproc_cost = threads * preproc_time * 2 * 10**9 / 100 # 100 cycles per node with SuppressStream(): r = [] for i in range(M.d): r_, exp = M.get_r_exp(i, i) r.append(r_ * 2**(exp - ph)) (cost, prob), coeffs = cls.pruning_coefficients( squared_target_norm / 2**ph, r, preproc_cost, target_prob=target_prob) def callbackf(v): nonlocal ntests ntests += 1 return predicate(v, standard_basis=False) enum_obj = Enumeration(M, callbackf=callbackf) with tracer.context("enumeration", enum_obj=enum_obj, probability=prob, full=True): try: solutions = enum_obj.enumerate(0, M.d, squared_target_norm / 2**ph, ph, pruning=coeffs) _, v = solutions[0] found = True solution = tuple([int(v_) for v_ in M.B.multiply_left(v)]) break except EnumerationError: pass rerandomize = True remaining_probability *= 1 - prob tracer.exit() FPLLL.set_threads(1) b0, b0e = bkz.M.get_r_exp(0, 0) return USVPPredSolverResults( success=found, solution=solution, ntests=ntests + bkz_res.ntests, b0=b0**(0.5) * 2**(b0e / 2.0), cputime=tracer.trace.data["cputime"] + bkz_res.cputime, walltime=tracer.trace.data["walltime"] + bkz_res.walltime, data=tracer.trace, )
def approx_svp_time(seed, params, return_queue=None, progressive=False): """Run Approx-SVP_{1.05} reduction on ``A`` using ``params``. :param seed: random seed for matrix creation :param params: BKZ preprocessing parameters, preprocessing block size is ignored :param return_queue: if not ``None``, the result is put on this queue. :param progressive: run Progressive-BKZ """ from chal import load_svp_challenge from fpylll.algorithms.bkz import BKZReduction as BKZBase FPLLL.set_random_seed(seed) A = load_svp_challenge(params.block_size, seed=seed) M = GSO.Mat(A) M.update_gso() gh = gaussian_heuristic(M.r()) target_norm = 1.05**2 * gh nodes_per_second = 2.0 * 10**9 / 100.0 self = BKZ2(M) tracer = BKZTreeTracer(self, start_clocks=True) rerandomize = False preproc_cost = None with tracer.context(("tour", 0)): while M.get_r(0, 0) > target_norm: with tracer.context("preprocessing"): if rerandomize: self.randomize_block( 1, params.block_size, density=params.rerandomization_density, tracer=tracer) with tracer.context("reduction"): BKZBase.svp_preprocessing(self, 0, params.block_size, params, tracer) # LLL preproc = round(0.9878 * params.block_size - 24.12) # curve fitted to chal.py output prepar = params.__class__(block_size=preproc, strategies=params.strategies, flags=BKZ.GH_BND) self.tour(prepar, 0, params.block_size, tracer=tracer) if preproc_cost is None: preproc_cost = float( tracer.trace.find("preprocessing")["walltime"]) preproc_cost *= nodes_per_second with tracer.context("pruner"): step_target = M.get_r(0, 0) * 0.99 if progressive else target_norm pruner = Pruning.Pruner(step_target, preproc_cost, [M.r()], target=1, metric=Pruning.EXPECTED_SOLUTIONS) coefficients = pruner.optimize_coefficients([1.] * M.d) try: enum_obj = Enumeration(self.M) with tracer.context("enumeration", enum_obj=enum_obj, full=True): max_dist, solution = enum_obj.enumerate( 0, params.block_size, target_norm, 0, pruning=coefficients)[0] with tracer.context("postprocessing"): self.svp_postprocessing(0, params.block_size, solution, tracer=tracer) rerandomize = False except EnumerationError: rerandomize = True self.M.update_gso() logger.debug("r_0: %7.2f, target: %7.2f, preproc: %3d" % (log(M.get_r(0, 0), 2), log(target_norm, 2), preproc)) tracer.exit() tracer.trace.data["|A_0|"] = A[0].norm() tracer.trace.data["preprocessing_block_size"] = preproc if return_queue: return_queue.put(tracer.trace) else: return tracer.trace