static int compute_min_prec(double &rho, int d, double delta, double eta, double epsilon, MinPrecAlgo algo) { int old_prec = Float::set_prec(53); Float f_minprec, f_rho, f_d, f_eta, f_delta, f_epsilon, tmp1, tmp2; // These four conversions are exact f_d = static_cast<double>(d); f_eta = eta; f_delta = delta; f_epsilon = epsilon; if (algo == MINPREC_L2) { // eta - 0.5 is an exact fp operation if (f_epsilon > eta - 0.5) f_epsilon = eta - 0.5; tmp1 = 1.0; tmp1.sub(tmp1, f_delta, GMP_RNDD); if (f_epsilon > tmp1) f_epsilon = tmp1; // now fEpsilon <= min(epsilon, eta - 0.5, 1 - delta); } // Computes tmp1 >= (1 + eta) ^ 2 + epsilon tmp1 = 1.0; // exact tmp1.add(f_eta, tmp1, GMP_RNDU); // >= 1 + eta tmp1.mul(tmp1, tmp1, GMP_RNDU); // >= (1 + eta) ^ 2 tmp1.add(tmp1, f_epsilon, GMP_RNDU); // Computes tmp2 <= delta - eta ^ 2 tmp2.mul(f_eta, f_eta, GMP_RNDU); tmp2.sub(f_delta, tmp2, GMP_RNDD); FPLLL_CHECK(tmp2 > 0, "invalid LLL parameters, eta must be < sqrt(delta)"); // Computes rho >= ((1 + eta) ^ 2 + epsilon) / (delta - eta ^ 2) f_rho.div(tmp1, tmp2, GMP_RNDU); rho = f_rho.get_d(GMP_RNDU); /* Computes minprec >= constant + 2 * log2(d) - log2(epsilon) + d * log2(rho) (constant = 5 for GSO, 10 for LLL) */ tmp1.log(f_d, GMP_RNDU); // >= log(d) tmp1.mul_2si(tmp1, 1); // >= 2 * log(d) tmp2.log(f_epsilon, GMP_RNDD); // <= log(epsilon) (<= 0) tmp1.sub(tmp1, tmp2, GMP_RNDU); // >= 2 * log(d) - log(epsilon) tmp2.log(f_rho, GMP_RNDU); // >= log(rho) tmp2.mul(f_d, tmp2, GMP_RNDU); // >= d * log(rho) tmp1.add(tmp1, tmp2, GMP_RNDU); // >= 2*log(d)-log(epsilon)+d*log(rho) tmp2 = 2.0; // exact tmp2.log(tmp2, GMP_RNDD); // <= log(2) tmp1.div(tmp1, tmp2, GMP_RNDU); // >= 2*log2(d)-log2(epsilon)+d*log2(rho) tmp2 = (algo == MINPREC_L2) ? 10.0 : 5.0; f_minprec.add(tmp1, tmp2, GMP_RNDU); int minprec = static_cast<int>(ceil(f_minprec.get_d(GMP_RNDU))); mpfr_free_cache(); Float::set_prec(old_prec); return minprec; }
void EnumerationDyn<FT>::enumerate(int first, int last, FT &fmaxdist, long fmaxdistexpo, const vector<FT> &target_coord, const vector<enumxt> &subtree, const vector<enumf> &pruning, bool _dual, bool subtree_reset) { bool solvingsvp = target_coord.empty(); dual = _dual; pruning_bounds = pruning; target = target_coord; if (last == -1) last = _gso.d; d = last - first; fx.resize(d); FPLLL_CHECK(d < maxdim, "enumerate: dimension is too high"); FPLLL_CHECK((solvingsvp || !dual), "CVP for dual not implemented! What does that even mean? "); FPLLL_CHECK((subtree.empty() || !dual), "Subtree enumeration for dual not implemented!"); resetflag = !_max_indices.empty(); if (resetflag) reset_depth = _max_indices[last - subtree.size() - 1]; if (solvingsvp) { for (int i = 0; i < d; ++i) center_partsum[i] = 0.0; } else { for (int i = 0; i < d; ++i) center_partsum[i] = target_coord[i + first].get_d(); } FT fr, fmu, fmaxdistnorm; long rexpo, normexp = -1; for (int i = 0; i < d; ++i) { fr = _gso.get_r_exp(i + first, i + first, rexpo); normexp = max(normexp, rexpo + fr.exponent()); } fmaxdistnorm.mul_2si(fmaxdist, dual ? normexp - fmaxdistexpo : fmaxdistexpo - normexp); maxdist = fmaxdistnorm.get_d(GMP_RNDU); _evaluator.set_normexp(normexp); if (dual) { for (int i = 0; i < d; ++i) { fr = _gso.get_r_exp(i + first, i + first, rexpo); fr.mul_2si(fr, rexpo - normexp); rdiag[d - i - 1] = enumf(1.0) / fr.get_d(); } for (int i = 0; i < d; ++i) { for (int j = i + 1; j < d; ++j) { _gso.get_mu(fmu, j + first, i + first); mut[d - j - 1][d - i - 1] = -fmu.get_d(); } } } else { for (int i = 0; i < d; ++i) { fr = _gso.get_r_exp(i + first, i + first, rexpo); fr.mul_2si(fr, rexpo - normexp); rdiag[i] = fr.get_d(); } for (int i = 0; i < d; ++i) { for (int j = i + 1; j < d; ++j) { _gso.get_mu(fmu, j + first, i + first); mut[i][j] = fmu.get_d(); } } } subsoldists = rdiag; save_rounding(); prepare_enumeration(subtree, solvingsvp, subtree_reset); do_enumerate(); restore_rounding(); fmaxdistnorm = maxdist; // Exact fmaxdist.mul_2si(fmaxdistnorm, dual ? fmaxdistexpo - normexp : normexp - fmaxdistexpo); if (dual && !_evaluator.empty()) { for (auto it = _evaluator.begin(), itend = _evaluator.end(); it != itend; ++it) reverse_by_swap(it->second, 0, d - 1); } }
static int shortest_vector_ex(IntMatrix &b, IntVect &sol_coord, SVPMethod method, const vector<double> &pruning, int flags, EvaluatorMode eval_mode, long long &sol_count, vector<IntVect> *subsol_coord = nullptr, vector<enumf> *subsol_dist = nullptr) { bool findsubsols = (subsol_coord != nullptr) && (subsol_dist != nullptr); // d = lattice dimension (note that it might decrease during preprocessing) int d = b.get_rows(); // n = dimension of the space int n = b.get_cols(); FPLLL_CHECK(d > 0 && n > 0, "shortestVector: empty matrix"); FPLLL_CHECK(d <= n, "shortestVector: number of vectors > size of the vectors"); // Sets the floating-point precision // Error bounds on GSO are valid if prec >= minprec double rho; int min_prec = gso_min_prec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA); int prec = max(53, min_prec + 10); int old_prec = Float::set_prec(prec); // Allocates space for vectors and matrices in constructors IntMatrix empty_mat; MatGSO<Integer, Float> gso(b, empty_mat, empty_mat, GSO_INT_GRAM); Float max_dist; Integer int_max_dist; Integer itmp1; // Computes the Gram-Schmidt orthogonalization in floating-point gso.update_gso(); gen_zero_vect(sol_coord, d); // If the last b_i* are too large, removes them to avoid an underflow int new_d = last_useful_index(gso.get_r_matrix()); if (new_d < d) { // FPLLL_TRACE("Ignoring the last " << d - new_d << " vector(s)"); d = new_d; } if (flags & SVP_DUAL) { max_dist = 1.0 / gso.get_r_exp(d - 1, d - 1); if (flags & SVP_VERBOSE) { cout << "max_dist = " << max_dist << endl; } } else { /* Computes a bound for the enumeration. This bound would work for an exact algorithm, but we will increase it later to ensure that the fp algorithm finds a solution */ get_basis_min(int_max_dist, b, 0, d); max_dist.set_z(int_max_dist, GMP_RNDU); } // Initializes the evaluator of solutions Evaluator<Float> *evaluator; if (method == SVPM_FAST) { evaluator = new FastEvaluator<Float>(d, gso.get_mu_matrix(), gso.get_r_matrix(), eval_mode, 0, findsubsols); } else if (method == SVPM_PROVED) { ExactEvaluator *p = new ExactEvaluator(d, b, gso.get_mu_matrix(), gso.get_r_matrix(), eval_mode, 0, findsubsols); p->int_max_dist = int_max_dist; evaluator = p; } else { FPLLL_ABORT("shortestVector: invalid evaluator type"); } evaluator->init_delta_def(prec, rho, true); if (!(flags & SVP_OVERRIDE_BND) && (eval_mode == EVALMODE_SV || method == SVPM_PROVED)) { Float ftmp1; bool result = evaluator->get_max_error_aux(max_dist, true, ftmp1); FPLLL_CHECK(result, "shortestVector: cannot compute an initial bound"); max_dist.add(max_dist, ftmp1, GMP_RNDU); } // Main loop of the enumeration enumerate_svp(d, gso, max_dist, *evaluator, pruning, flags); int result = RED_ENUM_FAILURE; if (eval_mode != EVALMODE_SV) { result = RED_SUCCESS; sol_count = evaluator->sol_count * 2; } else if (!evaluator->sol_coord.empty()) { /*Float fMaxError; validMaxError = evaluator->get_max_error(fMaxError); max_error = fMaxError.get_d(GMP_RNDU);*/ for (int i = 0; i < d; i++) { itmp1.set_f(evaluator->sol_coord[i]); sol_coord[i].add(sol_coord[i], itmp1); } result = RED_SUCCESS; } if (findsubsols) { subsol_coord->clear(); subsol_dist->clear(); subsol_dist->resize(evaluator->sub_sol_coord.size()); for (size_t i = 0; i < evaluator->sub_sol_coord.size(); ++i) { (*subsol_dist)[i] = evaluator->sub_sol_dist[i]; IntVect ss_c; for (size_t j = 0; j < evaluator->sub_sol_coord[i].size(); ++j) { itmp1.set_f(evaluator->sub_sol_coord[i][j]); ss_c.emplace_back(itmp1); } subsol_coord->emplace_back(std::move(ss_c)); } } delete evaluator; Float::set_prec(old_prec); return result; }
/** * interface called from call_bkz() from main.cpp. */ int bkz_reduction(IntMatrix *B, IntMatrix *U, const BKZParam ¶m, FloatType float_type, int precision) { IntMatrix empty_mat; IntMatrix &u = U ? *U : empty_mat; IntMatrix &u_inv = empty_mat; FPLLL_CHECK(B, "B == NULL in bkzReduction"); if (U && (!u.empty())) { u.gen_identity(B->get_rows()); } double lll_delta = param.delta < 1 ? param.delta : LLL_DEF_DELTA; FloatType sel_ft = (float_type != FT_DEFAULT) ? float_type : FT_DOUBLE; FPLLL_CHECK(!(sel_ft == FT_MPFR && precision == 0), "Missing precision for BKZ with floating point type mpfr"); /* lllwrapper (no FloatType needed, -m ignored) */ if (param.flags & BKZ_NO_LLL) zeros_last(*B, u, u_inv); else { Wrapper wrapper(*B, u, u_inv, lll_delta, LLL_DEF_ETA, LLL_DEFAULT); if (!wrapper.lll()) return wrapper.status; } /* bkz (with float_type) */ int status; if (sel_ft == FT_DOUBLE) { status = bkz_reduction_f<FP_NR<double>>(*B, param, sel_ft, lll_delta, u, u_inv); } #ifdef FPLLL_WITH_LONG_DOUBLE else if (sel_ft == FT_LONG_DOUBLE) { status = bkz_reduction_f<FP_NR<long double>>(*B, param, sel_ft, lll_delta, u, u_inv); } #endif #ifdef FPLLL_WITH_DPE else if (sel_ft == FT_DPE) { status = bkz_reduction_f<FP_NR<dpe_t>>(*B, param, sel_ft, lll_delta, u, u_inv); } #endif #ifdef FPLLL_WITH_QD else if (sel_ft == FT_DD) { status = bkz_reduction_f<FP_NR<dd_real>>(*B, param, sel_ft, lll_delta, u, u_inv); } else if (sel_ft == FT_QD) { status = bkz_reduction_f<FP_NR<qd_real>>(*B, param, sel_ft, lll_delta, u, u_inv); } #endif else if (sel_ft == FT_MPFR) { int old_prec = FP_NR<mpfr_t>::set_prec(precision); status = bkz_reduction_f<FP_NR<mpfr_t>>(*B, param, sel_ft, lll_delta, u, u_inv); FP_NR<mpfr_t>::set_prec(old_prec); } else { FPLLL_ABORT("Compiled without support for BKZ reduction with " << FLOAT_TYPE_STR[sel_ft]); } zeros_first(*B, u, u_inv); return status; }
int closest_vector(IntMatrix &b, const IntVect &int_target, IntVect &sol_coord, int method, int flags) { // d = lattice dimension (note that it might decrease during preprocessing) int d = b.get_rows(); // n = dimension of the space int n = b.get_cols(); FPLLL_CHECK(d > 0 && n > 0, "closestVector: empty matrix"); FPLLL_CHECK(d <= n, "closestVector: number of vectors > size of the vectors"); // Sets the floating-point precision // Error bounds on GSO are valid if prec >= minprec double rho; int min_prec = gso_min_prec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA); int prec = max(53, min_prec + 10); int old_prec = Float::set_prec(prec); // Allocates space for vectors and matrices in constructors IntMatrix empty_mat; MatGSO<Integer, Float> gso(b, empty_mat, empty_mat, GSO_INT_GRAM); FloatVect target_coord; Float max_dist; Integer itmp1; // Computes the Gram-Schmidt orthogonalization in floating-point gso.update_gso(); gen_zero_vect(sol_coord, d); /* Applies Babai's algorithm. Because we use fp, it might be necessary to do it several times (if ||target|| >> ||b_i||) */ FloatMatrix float_matrix(d, n); FloatVect target(n), babai_sol; IntVect int_new_target = int_target; for (int i = 0; i < d; i++) for (int j = 0; j < n; j++) float_matrix(i, j).set_z(b(i, j)); for (int loop_idx = 0;; loop_idx++) { if (loop_idx >= 0x100 && ((loop_idx & (loop_idx - 1)) == 0)) FPLLL_INFO("warning: possible infinite loop in Babai's algorithm"); for (int i = 0; i < n; i++) { target[i].set_z(int_new_target[i]); } babai(float_matrix, gso.get_mu_matrix(), gso.get_r_matrix(), target, babai_sol); int idx; for (idx = 0; idx < d && babai_sol[idx] >= -1 && babai_sol[idx] <= 1; idx++) { } if (idx == d) break; for (int i = 0; i < d; i++) { itmp1.set_f(babai_sol[i]); sol_coord[i].add(sol_coord[i], itmp1); for (int j = 0; j < n; j++) int_new_target[j].submul(itmp1, b(i, j)); } } // FPLLL_TRACE("BabaiSol=" << sol_coord); get_gscoords(float_matrix, gso.get_mu_matrix(), gso.get_r_matrix(), target, target_coord); /* Computes a very large bound to make the algorithm work until the first solution is found */ max_dist = 0.0; for (int i = 1; i < d; i++) { // get_r_exp(i, i) = r(i, i) because gso is initialized without GSO_ROW_EXPO max_dist.add(max_dist, gso.get_r_exp(i, i)); } vector<int> max_indices; if (method & CVPM_PROVED) { // For Exact CVP, we need to reset enum below depth with maximal r_i max_indices = vector<int>(d); int cur, max_index, previous_max_index; previous_max_index = max_index = d-1; Float max_val; while (max_index > 0) { max_val = gso.get_r_exp(max_index, max_index); for (cur = previous_max_index - 1 ; cur >= 0 ; --cur) { if (max_val <= gso.get_r_exp(cur, cur)) { max_val = gso.get_r_exp(cur, cur); max_index = cur; } } for (cur = max_index ; cur < previous_max_index ; ++cur) max_indices[cur] = max_index; max_indices[previous_max_index] = previous_max_index; previous_max_index = max_index; --max_index; } } FPLLL_TRACE("max_indices " << max_indices); FastEvaluator<Float> evaluator(n, gso.get_mu_matrix(), gso.get_r_matrix(), EVALMODE_CV); // Main loop of the enumeration Enumeration<Float> enumobj(gso, evaluator, max_indices); enumobj.enumerate(0, d, max_dist, 0, target_coord); int result = RED_ENUM_FAILURE; if (!evaluator.sol_coord.empty()) { FPLLL_TRACE("evaluator.sol_coord=" << evaluator.sol_coord); if (flags & CVP_VERBOSE) FPLLL_INFO("max_dist=" << max_dist); for (int i = 0; i < d; i++) { itmp1.set_f(evaluator.sol_coord[i]); sol_coord[i].add(sol_coord[i], itmp1); } result = RED_SUCCESS; } Float::set_prec(old_prec); return result; }