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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
    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 parallel_svp_reduction_worker(self, kappa, block_size, params,
                                      rerandomize):
        """
        One SVP reduction, typically called in a worker process after forking.

        :param kappa: current index
        :param block_size: block size
        :param params: BKZ parameters
        :param tracer: object for maintaining statistics

        """
        # we create a new tracer object to report back our timings to the calling process
        tracer = BKZTreeTracer(self,
                               verbosity=params.flags & BKZ.VERBOSE,
                               root_label="svp")

        with tracer.context("preprocessing"):
            if rerandomize:
                with tracer.context("randomization"):
                    self.randomize_block(
                        kappa + 1,
                        kappa + block_size,
                        density=params.rerandomization_density,
                        tracer=tracer)
            with tracer.context("reduction"):
                self.svp_preprocessing(kappa, block_size, params, tracer)

        radius, expo = self.M.get_r_exp(kappa, kappa)
        radius *= self.lll_obj.delta

        if params.flags & BKZ.GH_BND and block_size > 30:
            root_det = self.M.get_root_det(kappa, kappa + block_size)
            radius, expo = adjust_radius_to_gh_bound(radius, expo, block_size,
                                                     root_det,
                                                     params.gh_factor)

        pruning = self.get_pruning(kappa, block_size, params, tracer)

        try:
            enum_obj = Enumeration(self.M)
            with tracer.context("enumeration",
                                enum_obj=enum_obj,
                                probability=pruning.expectation,
                                full=block_size == params.block_size):
                max_dist, solution = enum_obj.enumerate(
                    kappa,
                    kappa + block_size,
                    radius,
                    expo,
                    pruning=pruning.coefficients)[0]
            with tracer.context("postprocessing"):
                # we translate our solution to the canonical basis because our basis is not
                # necessarily the basis of the calling process at this point
                solution = self.A.multiply_left(solution, start=kappa)

        except EnumerationError:
            solution, max_dist = None, None

        return solution, max_dist, tracer.trace, pruning.expectation
Beispiel #8
0
    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
Beispiel #9
0
def test_bkz_postprocessing():
    A = IntegerMatrix.random(20, "qary", bits=20, k=10, int_type="long")
    LLL.reduction(A)

    bkz = BKZ(A)
    bkz.M.update_gso()
    tracer = BKZTreeTracer(bkz)

    solution = (2, 2, 0, 3, 4, 5, 7)

    v = A.multiply_left(solution, 3)
    bkz.svp_postprocessing(3, len(solution), solution, tracer)
    w = tuple(A[3])
    assert v == w

    solution = (2, 1, 0, 3, 4, 5, 7)

    v = A.multiply_left(solution, 3)
    bkz.svp_postprocessing(3, len(solution), solution, tracer)
    w = tuple(A[3])
    assert v == w
Beispiel #10
0
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
Beispiel #12
0
    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,
        )
Beispiel #13
0
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