def __init__(self, A, ncores=2): """Create new BKZ object. :param A: an integer matrix, a GSO object or an LLL object :param ncores: number of cores to use """ self.ncores = ncores BKZ2.__init__(self, A)
def load_matrix_file(filepath, randomize=False, seed=None, float_type="double"): """ Load matrix from file, LLL reduce (and randomize). :param filepath: Load matrix from this file :param randomize: Randomize the basis :param seed: Seed for randomization :returns: lattice basis and BKZ object """ A = IntegerMatrix.from_file(filepath) A = LLL.reduction(A) A = IntegerMatrix.from_matrix(A, int_type="long") M = GSO.Mat(A, float_type=float_type) bkz = BKZReduction(M) if seed is not None: FPLLL.set_random_seed(seed) if randomize: bkz.randomize_block(0, A.nrows, density=A.ncols // 4) LLL.reduction(A) M = GSO.Mat(A, float_type=float_type) bkz = BKZReduction(M) bkz.lll_obj() # to initialize bkz.M etc return A, bkz
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 recycled_svp_preprocessing(self, kappa, block_size, param, stats, preproc_block_size): prepar = param.__class__(block_size=preproc_block_size, strategies=param.strategies, flags=BKZ.GH_BND) clean = BKZ2.tour(self, prepar, kappa, kappa + block_size) return clean
def load_challenge_and_randomize(n): A_pre = IntegerMatrix.from_file("svpchallenge/svpchallengedim%dseed0.txt" % n) LLL.reduction(A_pre) A = IntegerMatrix.from_matrix(A_pre, int_type="long") params = fplll_bkz.Param(block_size=n, max_loops=1, strategies=fplll_bkz.DEFAULT_STRATEGY, flags=fplll_bkz.GH_BND, min_success_probability=.8) bkz = BKZReduction(A) bkz.lll_obj() bkz.randomize_block(0, n, density=n / 4) bkz.lll_obj() return A, bkz
def load_prebkz(n, s=0, blocksize=40): """ """ filename = "qarychallenge/prebkz-%02d-dim-%03d-seed-%02d.txt" % (blocksize, n, s) if not os.path.isdir("qarychallenge"): os.mkdir("qarychallenge") if os.path.isfile(filename) is False: set_random_seed(s) A = IntegerMatrix.random(n, "qary", q=2**30, k=n // 2) print "Did not find '{filename}'. Creating and reducing".format( filename=filename) print "created, ", sys.stdout.flush() A = LLL.reduction(A) print "LLLed, ", sys.stdout.flush() if A.nrows >= 160: float_type = "long double" elif A.nrows >= 200: float_type = "dd" else: float_type = "double" M = GSO.Mat(A, float_type=float_type, flags=GSO.ROW_EXPO) bkz = BKZReduction(M) for b in range(10, blocksize + 1): print "\r created, LLLed, BKZed %d" % b, sys.stdout.flush() par = fplll_bkz.Param(b, strategies=fplll_bkz.DEFAULT_STRATEGY, max_loops=1, flags=fplll_bkz.MAX_LOOPS) bkz(par) print fn = open(filename, "w") fn.write(str(A)) fn.close() return load_matrix_file(filename, randomize=False)
def svp_preprocessing(self, kappa, block_size, param, tracer=dummy_tracer): """ Run sequential BKZ 2.0 preprocessing. :param kappa: current index :param block_size: block size :param params: BKZ parameters :param tracer: object for maintaining statistics """ clean = True clean &= BKZ1.svp_preprocessing(self, kappa, block_size, param, tracer) for preproc in param.strategies[block_size].preprocessing_block_sizes: prepar = param.__class__(block_size=preproc, strategies=param.strategies, flags=BKZ.GH_BND) clean &= BKZ2.tour(self, prepar, kappa, kappa + block_size) return clean
def get_pruning(self, kappa, block_size, param, stats): """ Ask for pruning parameters from coordinating process. :param kappa: index :param block_size: block size :param param: access to strategy objects :param stats: passed on """ strategy = param.strategies[block_size] radius = self.M.get_r(kappa, kappa) * self.lll_obj.delta r = [self.M.get_r(i, i) for i in range(kappa, kappa+block_size)] gh_radius = gaussian_heuristic(r) if (param.flags & BKZ.GH_BND and block_size > 30): radius = min(radius, gh_radius * param.gh_factor) try: ret = radius, 0, strategy.get_pruning(tuple(r), radius, stats, param.min_success_probability) except TypeError: ret = BKZ2.get_pruning(self, kappa, block_size, param, stats) return ret
def get_pruning(self, kappa, block_size, param, stats): """ Ask for pruning parameters from coordinating process. :param kappa: index :param block_size: block size :param param: access to strategy objects :param stats: passed on """ strategy = param.strategies[block_size] radius = self.M.get_r(kappa, kappa) * self.lll_obj.delta r = [self.M.get_r(i, i) for i in range(kappa, kappa+block_size)] gh_radius = gaussian_heuristic(r) if (param.flags & BKZ.GH_BND and block_size > 30): radius = min(radius, gh_radius * param.gh_factor) try: ret = radius, strategy.get_pruning(tuple(r), radius, stats, param.min_success_probability) except TypeError: ret = BKZ2.get_pruning(self, kappa, block_size, param, stats) return ret
r0 = bkz.M.get_r(0, 0) print "OPPORT_ENUM", { "n": n, "Time": round(ENUM_TIME, 2), "ghf": round(r0 / gh, 4) } AV_ENUM += ENUM_TIME / sample_rep ########### Timing SubSieve A, bkz = load_challenge_and_randomize(n) SUBSIEVE_START = time() d = iterated_sub_sieve(A, goal=goal) SUBSIEVE_TIME = time() - SUBSIEVE_START bkz = BKZReduction(A) bkz.lll_obj() r0 = bkz.M.get_r(0, 0) print "SUB_SIEVE ", { "n": n, "Time": round(SUBSIEVE_TIME, 2), "ghf": round(r0 / gh, 4) }, { "d": d } AV_SIEVE += SUBSIEVE_TIME / sample_rep print print "OPPORT_ENUM average :", AV_ENUM print "SUB_SIEVE average :", AV_SIEVE
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.")
# -*- coding: utf-8 -*- from fpylll import IntegerMatrix, LLL, GSO from fpylll import BKZ as fplll_bkz from fpylll.algorithms.bkz2 import BKZReduction from fpylll.tools.bkz_stats import dummy_tracer from time import time from fpylll import Enumeration, EnumerationError import sys from fpylll.util import gaussian_heuristic from middleware import SubSieveLib for n in range(40, 90, 2): A_pre = IntegerMatrix.from_file("svpchallenge/svpchallengedim%dseed0.txt" % n) LLL.reduction(A_pre) A = IntegerMatrix.from_matrix(A_pre, int_type="long") bkz = BKZReduction(A) bkz.lll_obj() bkz.randomize_block(0, n, density=n / 4) bkz.lll_obj() START = time() siever = SubSieveLib(n, 0, bkz.lll_obj.M) siever.sieve() TIME = time() - START print(n, TIME) del siever
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 __init__(self, A, recycling_pool_max_size=1): """Create new BKZ object. :param A: an integer matrix, a GSO object or an LLL object """ BKZ2.__init__(self, A) self.recycling_pool_max_size = recycling_pool_max_size