1 /* Copyright (C) 2008-2011 Xavier Pujol.
2 (C) 2015 Michael Walter.
3 Copyright (C) 2019 Koen de Boer & Wessel van Woerden
4
5 This file is part of fplll. fplll is free software: you
6 can redistribute it and/or modify it under the terms of the GNU Lesser
7 General Public License as published by the Free Software Foundation,
8 either version 2.1 of the License, or (at your option) any later version.
9
10 fplll is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with fplll. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "svpcvp.h"
19 #include "enum/enumerate.h"
20 #include "enum/topenum.h"
21
22 FPLLL_BEGIN_NAMESPACE
23
24 /* Shortest vector problem
25 ======================= */
26
27 /* Returns i such that the shortest vector of L(b) belongs to
28 L(b_0,...,b_(i-1)), assuming that the error on rdiag's is less than 100%.
29 If b is LLL-reduced, then for any reasonnable dimension,
30 max(rdiag[0],...,rdiag[i-1]) / min(rdiag[0],...,rdiag[i-1])
31 is much smaller than numeric_limits<double>::max */
last_useful_index(const Matrix<FP_NR<mpfr_t>> & r)32 static int last_useful_index(const Matrix<FP_NR<mpfr_t>> &r)
33 {
34 int i;
35 FP_NR<mpfr_t> rdiag_min_value;
36 rdiag_min_value.mul_2si(r(0, 0), 1);
37 for (i = r.get_rows() - 1; i > 0; i--)
38 {
39 if (r(i, i) <= rdiag_min_value)
40 break;
41 }
42 return i + 1;
43 }
44
45 /* Finds the shortest vector of the basis b and returns its squared norm in
46 basisMin */
get_basis_min(Z_NR<mpz_t> & basis_min,const ZZ_mat<mpz_t> & b,int first,int last)47 static void get_basis_min(Z_NR<mpz_t> &basis_min, const ZZ_mat<mpz_t> &b, int first, int last)
48 {
49 Z_NR<mpz_t> sq_norm;
50 int n = b.get_cols();
51 b[first].dot_product(basis_min, b[first], n);
52
53 for (int i = first + 1; i < last; i++)
54 {
55 b[i].dot_product(sq_norm, b[i], n);
56 if (sq_norm < basis_min)
57 basis_min = sq_norm;
58 }
59 }
60
get_basis_min(Z_NR<mpz_t> & basis_min,MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,int first,int last)61 static void get_basis_min(Z_NR<mpz_t> &basis_min, MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
62 int first, int last)
63 {
64 Z_NR<mpz_t> sq_norm;
65 gso.get_int_gram(basis_min, first, first);
66 for (int i = first + 1; i < last; i++)
67 {
68 gso.get_int_gram(sq_norm, i, i);
69 if (sq_norm < basis_min)
70 basis_min = sq_norm;
71 }
72 }
73
enumerate_svp(int d,MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,FP_NR<mpfr_t> & max_dist,ErrorBoundedEvaluator & evaluator,const vector<enumf> & pruning,int flags)74 static bool enumerate_svp(int d, MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
75 FP_NR<mpfr_t> &max_dist, ErrorBoundedEvaluator &evaluator,
76 const vector<enumf> &pruning, int flags)
77 {
78 Enumeration<Z_NR<mpz_t>, FP_NR<mpfr_t>> enumobj(gso, evaluator);
79 bool dual = (flags & SVP_DUAL);
80 enumobj.enumerate(0, d, max_dist, 0, vector<FP_NR<mpfr_t>>(), vector<enumxt>(), pruning, dual);
81 return !evaluator.empty();
82 }
83
shortest_vector_ex(ZZ_mat<mpz_t> & b,vector<Z_NR<mpz_t>> & sol_coord,SVPMethod method,const vector<double> & pruning,int flags,EvaluatorMode eval_mode,long long & sol_count,vector<vector<Z_NR<mpz_t>>> * subsol_coord=nullptr,vector<enumf> * subsol_dist=nullptr,vector<vector<Z_NR<mpz_t>>> * auxsol_coord=nullptr,vector<enumf> * auxsol_dist=nullptr,int max_aux_sols=0)84 static int shortest_vector_ex(ZZ_mat<mpz_t> &b, vector<Z_NR<mpz_t>> &sol_coord, SVPMethod method,
85 const vector<double> &pruning, int flags, EvaluatorMode eval_mode,
86 long long &sol_count,
87 vector<vector<Z_NR<mpz_t>>> *subsol_coord = nullptr,
88 vector<enumf> *subsol_dist = nullptr,
89 vector<vector<Z_NR<mpz_t>>> *auxsol_coord = nullptr,
90 vector<enumf> *auxsol_dist = nullptr, int max_aux_sols = 0)
91 {
92 bool findsubsols = (subsol_coord != nullptr) && (subsol_dist != nullptr);
93 bool findauxsols = (auxsol_coord != nullptr) && (auxsol_dist != nullptr) && (max_aux_sols != 0);
94
95 // d = lattice dimension (note that it might decrease during preprocessing)
96 int d = b.get_rows();
97 // n = dimension of the space
98 int n = b.get_cols();
99
100 FPLLL_CHECK(d > 0 && n > 0, "shortestVector: empty matrix");
101 FPLLL_CHECK(d <= n, "shortestVector: number of vectors > size of the vectors");
102
103 // Sets the floating-point precision
104 // Error bounds on GSO are valid if prec >= minprec
105 double rho;
106 int min_prec = gso_min_prec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
107 int prec = max(53, min_prec + 10);
108 int old_prec = FP_NR<mpfr_t>::set_prec(prec);
109
110 // Allocates space for vectors and matrices in constructors
111 ZZ_mat<mpz_t> empty_mat;
112 MatGSO<Z_NR<mpz_t>, FP_NR<mpfr_t>> gso(b, empty_mat, empty_mat, GSO_INT_GRAM);
113 FP_NR<mpfr_t> max_dist;
114 Z_NR<mpz_t> int_max_dist;
115 Z_NR<mpz_t> itmp1;
116
117 // Computes the Gram-Schmidt orthogonalization in floating-point
118 gso.update_gso();
119 gen_zero_vect(sol_coord, d);
120
121 // If the last b_i* are too large, removes them to avoid an underflow
122 int new_d = last_useful_index(gso.get_r_matrix());
123 if (new_d < d)
124 {
125 // FPLLL_TRACE("Ignoring the last " << d - new_d << " vector(s)");
126 d = new_d;
127 }
128
129 if (flags & SVP_DUAL)
130 {
131 max_dist = 1.0 / gso.get_r_exp(d - 1, d - 1);
132 if (flags & SVP_VERBOSE)
133 {
134 cout << "max_dist = " << max_dist << endl;
135 }
136 }
137 else
138 {
139 /* Computes a bound for the enumeration. This bound would work for an
140 exact algorithm, but we will increase it later to ensure that the fp
141 algorithm finds a solution */
142 get_basis_min(int_max_dist, b, 0, d);
143 max_dist.set_z(int_max_dist, GMP_RNDU);
144 }
145
146 // Initializes the evaluator of solutions
147 ErrorBoundedEvaluator *evaluator;
148 if (method == SVPM_FAST)
149 {
150 evaluator =
151 new FastErrorBoundedEvaluator(d, gso.get_mu_matrix(), gso.get_r_matrix(), eval_mode,
152 max_aux_sols + 1, EVALSTRATEGY_BEST_N_SOLUTIONS, findsubsols);
153 }
154 else if (method == SVPM_PROVED)
155 {
156 ExactErrorBoundedEvaluator *p = new ExactErrorBoundedEvaluator(
157 // d, b, gso.get_mu_matrix(), gso.get_r_matrix()
158 d, gso, eval_mode, max_aux_sols + 1, EVALSTRATEGY_BEST_N_SOLUTIONS, findsubsols);
159 p->int_max_dist = int_max_dist;
160 evaluator = p;
161 }
162 else
163 {
164 FPLLL_ABORT("shortestVector: invalid evaluator type");
165 }
166 evaluator->init_delta_def(prec, rho, true);
167
168 if (!(flags & SVP_OVERRIDE_BND) && (eval_mode == EVALMODE_SV || method == SVPM_PROVED))
169 {
170 FP_NR<mpfr_t> ftmp1;
171 bool result = evaluator->get_max_error_aux(max_dist, true, ftmp1);
172 FPLLL_CHECK(result, "shortestVector: cannot compute an initial bound");
173 max_dist.add(max_dist, ftmp1, GMP_RNDU);
174 }
175
176 // Main loop of the enumeration
177 enumerate_svp(d, gso, max_dist, *evaluator, pruning, flags);
178
179 int result = RED_ENUM_FAILURE;
180 if (eval_mode != EVALMODE_SV)
181 {
182 result = RED_SUCCESS;
183 sol_count = evaluator->sol_count * 2;
184 }
185 else if (!evaluator->empty())
186 {
187 /*FP_NR<mpfr_t> fMaxError;
188 validMaxError = evaluator->get_max_error(fMaxError);
189 max_error = fMaxError.get_d(GMP_RNDU);*/
190 for (int i = 0; i < d; i++)
191 {
192 itmp1.set_f(evaluator->begin()->second[i]);
193 sol_coord[i].add(sol_coord[i], itmp1);
194 }
195 result = RED_SUCCESS;
196 }
197
198 if (findsubsols)
199 {
200 subsol_coord->clear();
201 subsol_dist->clear();
202 subsol_dist->resize(evaluator->sub_solutions.size());
203 for (size_t i = 0; i < evaluator->sub_solutions.size(); ++i)
204 {
205 (*subsol_dist)[i] = evaluator->sub_solutions[i].first.get_d();
206
207 vector<Z_NR<mpz_t>> ss_c;
208 for (size_t j = 0; j < evaluator->sub_solutions[i].second.size(); ++j)
209 {
210 itmp1.set_f(evaluator->sub_solutions[i].second[j]);
211 ss_c.emplace_back(itmp1);
212 }
213 subsol_coord->emplace_back(std::move(ss_c));
214 }
215 }
216 if (findauxsols)
217 {
218 auxsol_coord->clear();
219 auxsol_dist->clear();
220 // iterators over all solutions
221 auto it = evaluator->begin(), itend = evaluator->end();
222 // skip shortest solution
223 ++it;
224 for (; it != itend; ++it)
225 {
226 auxsol_dist->push_back(it->first.get_d());
227
228 vector<Z_NR<mpz_t>> as_c;
229 for (size_t j = 0; j < it->second.size(); ++j)
230 {
231 itmp1.set_f(it->second[j]);
232 as_c.emplace_back(itmp1);
233 }
234 auxsol_coord->emplace_back(std::move(as_c));
235 }
236 }
237
238 delete evaluator;
239 FP_NR<mpfr_t>::set_prec(old_prec);
240 return result;
241 }
242
shortest_vector(ZZ_mat<mpz_t> & b,vector<Z_NR<mpz_t>> & sol_coord,SVPMethod method,int flags)243 int shortest_vector(ZZ_mat<mpz_t> &b, vector<Z_NR<mpz_t>> &sol_coord, SVPMethod method, int flags)
244 {
245 long long tmp;
246 return shortest_vector_ex(b, sol_coord, method, vector<double>(), flags, EVALMODE_SV, tmp);
247 }
248
shortest_vector_pruning(ZZ_mat<mpz_t> & b,vector<Z_NR<mpz_t>> & sol_coord,const vector<double> & pruning,int flags)249 int shortest_vector_pruning(ZZ_mat<mpz_t> &b, vector<Z_NR<mpz_t>> &sol_coord,
250 const vector<double> &pruning, int flags)
251 {
252 long long tmp;
253 return shortest_vector_ex(b, sol_coord, SVPM_FAST, pruning, flags, EVALMODE_SV, tmp);
254 }
255
shortest_vector_pruning(ZZ_mat<mpz_t> & b,vector<Z_NR<mpz_t>> & sol_coord,vector<vector<Z_NR<mpz_t>>> & subsol_coord,vector<enumf> & subsol_dist,const vector<double> & pruning,int flags)256 int shortest_vector_pruning(ZZ_mat<mpz_t> &b, vector<Z_NR<mpz_t>> &sol_coord,
257 vector<vector<Z_NR<mpz_t>>> &subsol_coord, vector<enumf> &subsol_dist,
258 const vector<double> &pruning, int flags)
259 {
260 long long tmp;
261 return shortest_vector_ex(b, sol_coord, SVPM_FAST, pruning, flags, EVALMODE_SV, tmp,
262 &subsol_coord, &subsol_dist);
263 }
264
shortest_vector_pruning(ZZ_mat<mpz_t> & b,vector<Z_NR<mpz_t>> & sol_coord,vector<vector<Z_NR<mpz_t>>> & auxsol_coord,vector<enumf> & auxsol_dist,const int max_aux_sols,const vector<double> & pruning,int flags)265 int shortest_vector_pruning(ZZ_mat<mpz_t> &b, vector<Z_NR<mpz_t>> &sol_coord,
266 vector<vector<Z_NR<mpz_t>>> &auxsol_coord, vector<enumf> &auxsol_dist,
267 const int max_aux_sols, const vector<double> &pruning, int flags)
268 {
269 long long tmp;
270 return shortest_vector_ex(b, sol_coord, SVPM_FAST, pruning, flags, EVALMODE_SV, tmp, nullptr,
271 nullptr, &auxsol_coord, &auxsol_dist, max_aux_sols);
272 }
273
274 //////////////////////////////////////////
275 ////// SVP FOR GSO OBJECT ///////////////
276 //////////////////////////////////////////
277
shortest_vector_ex(MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,vector<Z_NR<mpz_t>> & sol_coord,SVPMethod method,const vector<double> & pruning,int flags,EvaluatorMode eval_mode,long long & sol_count,vector<vector<Z_NR<mpz_t>>> * subsol_coord=nullptr,vector<enumf> * subsol_dist=nullptr,vector<vector<Z_NR<mpz_t>>> * auxsol_coord=nullptr,vector<enumf> * auxsol_dist=nullptr,int max_aux_sols=0,bool merge_sol_in_aux=false)278 static int shortest_vector_ex(
279 MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso, vector<Z_NR<mpz_t>> &sol_coord,
280 SVPMethod method, const vector<double> &pruning, int flags, EvaluatorMode eval_mode,
281 long long &sol_count, vector<vector<Z_NR<mpz_t>>> *subsol_coord = nullptr,
282 vector<enumf> *subsol_dist = nullptr, vector<vector<Z_NR<mpz_t>>> *auxsol_coord = nullptr,
283 vector<enumf> *auxsol_dist = nullptr, int max_aux_sols = 0, bool merge_sol_in_aux = false)
284 {
285 bool findsubsols = (subsol_coord != nullptr) && (subsol_dist != nullptr);
286 bool findauxsols = (auxsol_coord != nullptr) && (auxsol_dist != nullptr) && (max_aux_sols != 0);
287
288 // d = lattice dimension (note that it might decrease during preprocessing)
289 // int d = b.get_rows();
290 int d = gso.d; // Number of rows of b in the GSO
291
292 // n = dimension of the space
293 // int n = b.get_cols();
294 int n = gso.get_cols_of_b(); // number of columns of b in the GSO
295
296 FPLLL_CHECK(d > 0 && n > 0, "shortestVector: empty matrix");
297 FPLLL_CHECK(d <= n, "shortestVector: number of vectors > size of the vectors");
298
299 // Sets the floating-point precision
300 // Error bounds on GSO are valid if prec >= minprec
301 double rho;
302 int min_prec = gso_min_prec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
303 int prec = max(53, min_prec + 10);
304 int old_prec = FP_NR<mpfr_t>::set_prec(prec);
305
306 // Allocates space for vectors and matrices in constructors
307 FP_NR<mpfr_t> max_dist;
308 Z_NR<mpz_t> int_max_dist;
309 Z_NR<mpz_t> itmp1;
310
311 // Computes the Gram-Schmidt orthogonalization in floating-point
312 gso.update_gso();
313 gen_zero_vect(sol_coord, d);
314
315 // If the last b_i* are too large, removes them to avoid an underflow
316 int new_d = last_useful_index(gso.get_r_matrix());
317 if (new_d < d)
318 {
319 // FPLLL_TRACE("Ignoring the last " << d - new_d << " vector(s)");
320 d = new_d;
321 }
322
323 if (flags & SVP_DUAL)
324 {
325 max_dist = 1.0 / gso.get_r_exp(d - 1, d - 1);
326 if (flags & SVP_VERBOSE)
327 {
328 cout << "max_dist = " << max_dist << endl;
329 }
330 }
331 else
332 {
333 // Computes a bound for the enumeration. This bound would work for an
334 // exact algorithm, but we will increase it later to ensure that the fp
335 // algorithm finds a solution
336
337 // Use the GSO version of get_basis_min
338 get_basis_min(int_max_dist, gso, 0, d);
339 max_dist.set_z(int_max_dist, GMP_RNDU);
340 }
341
342 // Initializes the evaluator of solutions
343 ErrorBoundedEvaluator *evaluator;
344 if (method == SVPM_FAST)
345 {
346 evaluator =
347 new FastErrorBoundedEvaluator(d, gso.get_mu_matrix(), gso.get_r_matrix(), eval_mode,
348 max_aux_sols + 1, EVALSTRATEGY_BEST_N_SOLUTIONS, findsubsols);
349 }
350 else if (method == SVPM_PROVED)
351 {
352 ExactErrorBoundedEvaluator *p = new ExactErrorBoundedEvaluator(
353 d, gso, eval_mode, max_aux_sols + 1, EVALSTRATEGY_BEST_N_SOLUTIONS, findsubsols);
354 p->int_max_dist = int_max_dist;
355 evaluator = p;
356 }
357 else
358 {
359 FPLLL_ABORT("shortestVector: invalid evaluator type");
360 }
361 evaluator->init_delta_def(prec, rho, true);
362
363 if (!(flags & SVP_OVERRIDE_BND) && (eval_mode == EVALMODE_SV || method == SVPM_PROVED))
364 {
365 FP_NR<mpfr_t> ftmp1;
366 bool result = evaluator->get_max_error_aux(max_dist, true, ftmp1);
367 FPLLL_CHECK(result, "shortestVector: cannot compute an initial bound");
368 max_dist.add(max_dist, ftmp1, GMP_RNDU);
369 }
370
371 // Main loop of the enumeration
372 enumerate_svp(d, gso, max_dist, *evaluator, pruning, flags); // Only uses r and mu
373
374 int result = RED_ENUM_FAILURE;
375 if (eval_mode != EVALMODE_SV)
376 {
377 result = RED_SUCCESS;
378 sol_count = evaluator->sol_count * 2;
379 }
380 else if (!evaluator->empty())
381 {
382 // FP_NR<mpfr_t> fMaxError;
383 // validMaxError = evaluator->get_max_error(fMaxError);
384 // max_error = fMaxError.get_d(GMP_RNDU);
385 for (int i = 0; i < d; i++)
386 {
387 itmp1.set_f(evaluator->begin()->second[i]);
388 sol_coord[i].add(sol_coord[i], itmp1);
389 }
390 result = RED_SUCCESS;
391 }
392
393 if (findsubsols)
394 {
395 subsol_coord->clear();
396 subsol_dist->clear();
397 subsol_dist->resize(evaluator->sub_solutions.size());
398 for (size_t i = 0; i < evaluator->sub_solutions.size(); ++i)
399 {
400 (*subsol_dist)[i] = evaluator->sub_solutions[i].first.get_d();
401
402 vector<Z_NR<mpz_t>> ss_c;
403 for (size_t j = 0; j < evaluator->sub_solutions[i].second.size(); ++j)
404 {
405 itmp1.set_f(evaluator->sub_solutions[i].second[j]);
406 ss_c.emplace_back(itmp1);
407 }
408 subsol_coord->emplace_back(std::move(ss_c));
409 }
410 }
411 if (findauxsols)
412 {
413 auxsol_coord->clear();
414 auxsol_dist->clear();
415 // iterators over all solutions
416 auto it = evaluator->begin(), itend = evaluator->end();
417 // skip shortest solution
418 if (!merge_sol_in_aux)
419 ++it;
420 for (; it != itend; ++it)
421 {
422 auxsol_dist->push_back(it->first.get_d());
423
424 vector<Z_NR<mpz_t>> as_c;
425 for (size_t j = 0; j < it->second.size(); ++j)
426 {
427 itmp1.set_f(it->second[j]);
428 as_c.emplace_back(itmp1);
429 }
430 auxsol_coord->emplace_back(std::move(as_c));
431 }
432 }
433
434 delete evaluator;
435 FP_NR<mpfr_t>::set_prec(old_prec);
436 return result;
437 }
438
shortest_vector(MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,vector<Z_NR<mpz_t>> & sol_coord,SVPMethod method,int flags)439 int shortest_vector(MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
440 vector<Z_NR<mpz_t>> &sol_coord, SVPMethod method, int flags)
441 {
442 long long tmp;
443 return shortest_vector_ex(gso, sol_coord, method, vector<double>(), flags, EVALMODE_SV, tmp);
444 }
445
shortest_vectors(MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,vector<vector<Z_NR<mpz_t>>> & sol_coord,vector<enumf> & sol_dist,const int max_sols,SVPMethod method,int flags)446 int shortest_vectors(MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
447 vector<vector<Z_NR<mpz_t>>> &sol_coord, vector<enumf> &sol_dist,
448 const int max_sols, SVPMethod method, int flags)
449 {
450 long long tmp;
451 vector<Z_NR<mpz_t>> sol_coord_tmp;
452 return shortest_vector_ex(gso, sol_coord_tmp, method, vector<double>(), flags, EVALMODE_SV, tmp,
453 nullptr, nullptr, &sol_coord, &sol_dist, max_sols - 1, true);
454 }
455
shortest_vector_pruning(MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,vector<Z_NR<mpz_t>> & sol_coord,const vector<double> & pruning,int flags)456 int shortest_vector_pruning(MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
457 vector<Z_NR<mpz_t>> &sol_coord, const vector<double> &pruning,
458 int flags)
459 {
460 long long tmp;
461 return shortest_vector_ex(gso, sol_coord, SVPM_FAST, pruning, flags, EVALMODE_SV, tmp);
462 }
463
shortest_vector_pruning(MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,vector<Z_NR<mpz_t>> & sol_coord,vector<vector<Z_NR<mpz_t>>> & subsol_coord,vector<enumf> & subsol_dist,const vector<double> & pruning,int flags)464 int shortest_vector_pruning(MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
465 vector<Z_NR<mpz_t>> &sol_coord,
466 vector<vector<Z_NR<mpz_t>>> &subsol_coord, vector<enumf> &subsol_dist,
467 const vector<double> &pruning, int flags)
468 {
469 long long tmp;
470 return shortest_vector_ex(gso, sol_coord, SVPM_FAST, pruning, flags, EVALMODE_SV, tmp,
471 &subsol_coord, &subsol_dist);
472 }
473
shortest_vector_pruning(MatGSOInterface<Z_NR<mpz_t>,FP_NR<mpfr_t>> & gso,vector<Z_NR<mpz_t>> & sol_coord,vector<vector<Z_NR<mpz_t>>> & auxsol_coord,vector<enumf> & auxsol_dist,const int max_aux_sols,const vector<double> & pruning,int flags)474 int shortest_vector_pruning(MatGSOInterface<Z_NR<mpz_t>, FP_NR<mpfr_t>> &gso,
475 vector<Z_NR<mpz_t>> &sol_coord,
476 vector<vector<Z_NR<mpz_t>>> &auxsol_coord, vector<enumf> &auxsol_dist,
477 const int max_aux_sols, const vector<double> &pruning, int flags)
478 {
479 long long tmp;
480 return shortest_vector_ex(gso, sol_coord, SVPM_FAST, pruning, flags, EVALMODE_SV, tmp, nullptr,
481 nullptr, &auxsol_coord, &auxsol_dist, max_aux_sols);
482 }
483
484 ///////////////////////////////////
485 //////END SVP FOR GSO OBJECT //////
486 ///////////////////////////////////
487
488 /* Closest vector problem
489 ====================== */
490
get_gscoords(const Matrix<FP_NR<mpfr_t>> & matrix,const Matrix<FP_NR<mpfr_t>> & mu,const Matrix<FP_NR<mpfr_t>> & r,const vector<FP_NR<mpfr_t>> & v,vector<FP_NR<mpfr_t>> & vcoord)491 static void get_gscoords(const Matrix<FP_NR<mpfr_t>> &matrix, const Matrix<FP_NR<mpfr_t>> &mu,
492 const Matrix<FP_NR<mpfr_t>> &r, const vector<FP_NR<mpfr_t>> &v,
493 vector<FP_NR<mpfr_t>> &vcoord)
494 {
495
496 int n = matrix.get_rows(), m = matrix.get_cols();
497
498 if (static_cast<int>(vcoord.size()) != n)
499 vcoord.resize(n);
500 FPLLL_DEBUG_CHECK(mu.get_rows() == n && mu.get_cols() == n && r.get_rows() == n &&
501 r.get_cols() == n && static_cast<int>(v.size()) == m);
502
503 for (int i = 0; i < n; i++)
504 {
505 vcoord[i] = 0.0;
506 for (int j = 0; j < m; j++)
507 vcoord[i].addmul(v[j], matrix(i, j));
508 for (int j = 0; j < i; j++)
509 vcoord[i].submul(mu(i, j), vcoord[j]);
510 }
511 for (int i = 0; i < n; i++)
512 {
513 vcoord[i].div(vcoord[i], r(i, i));
514 }
515 }
516
babai(const FP_mat<mpfr_t> & matrix,const Matrix<FP_NR<mpfr_t>> & mu,const Matrix<FP_NR<mpfr_t>> & r,const vector<FP_NR<mpfr_t>> & target,vector<FP_NR<mpfr_t>> & target_coord)517 static void babai(const FP_mat<mpfr_t> &matrix, const Matrix<FP_NR<mpfr_t>> &mu,
518 const Matrix<FP_NR<mpfr_t>> &r, const vector<FP_NR<mpfr_t>> &target,
519 vector<FP_NR<mpfr_t>> &target_coord)
520 {
521
522 int d = matrix.get_rows();
523 get_gscoords(matrix, mu, r, target, target_coord);
524 for (int i = d - 1; i >= 0; i--)
525 {
526 target_coord[i].rnd(target_coord[i]);
527 for (int j = 0; j < i; j++)
528 target_coord[j].submul(mu(i, j), target_coord[i]);
529 }
530 }
531
closest_vector(ZZ_mat<mpz_t> & b,const vector<Z_NR<mpz_t>> & int_target,vector<Z_NR<mpz_t>> & sol_coord,int method,int flags)532 int closest_vector(ZZ_mat<mpz_t> &b, const vector<Z_NR<mpz_t>> &int_target,
533 vector<Z_NR<mpz_t>> &sol_coord, int method, int flags)
534 {
535 // d = lattice dimension (note that it might decrease during preprocessing)
536 int d = b.get_rows();
537 // n = dimension of the space
538 int n = b.get_cols();
539
540 FPLLL_CHECK(d > 0 && n > 0, "closestVector: empty matrix");
541 FPLLL_CHECK(d <= n, "closestVector: number of vectors > size of the vectors");
542
543 // Sets the floating-point precision
544 // Error bounds on GSO are valid if prec >= minprec
545 double rho;
546 int min_prec = gso_min_prec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
547 int prec = max(53, min_prec + 10);
548 int old_prec = FP_NR<mpfr_t>::set_prec(prec);
549
550 // Allocates space for vectors and matrices in constructors
551 ZZ_mat<mpz_t> empty_mat;
552 MatGSO<Z_NR<mpz_t>, FP_NR<mpfr_t>> gso(b, empty_mat, empty_mat, GSO_INT_GRAM);
553 vector<FP_NR<mpfr_t>> target_coord;
554 FP_NR<mpfr_t> max_dist;
555 Z_NR<mpz_t> itmp1;
556
557 // Computes the Gram-Schmidt orthogonalization in floating-point
558 gso.update_gso();
559 gen_zero_vect(sol_coord, d);
560
561 /* Applies Babai's algorithm. Because we use fp, it might be necessary to
562 do it several times (if ||target|| >> ||b_i||) */
563 FP_mat<mpfr_t> float_matrix(d, n);
564 vector<FP_NR<mpfr_t>> target(n), babai_sol;
565 vector<Z_NR<mpz_t>> int_new_target = int_target;
566
567 for (int i = 0; i < d; i++)
568 for (int j = 0; j < n; j++)
569 float_matrix(i, j).set_z(b(i, j));
570
571 for (int loop_idx = 0;; loop_idx++)
572 {
573 if (loop_idx >= 0x100 && ((loop_idx & (loop_idx - 1)) == 0))
574 FPLLL_INFO("warning: possible infinite loop in Babai's algorithm");
575
576 for (int i = 0; i < n; i++)
577 {
578 target[i].set_z(int_new_target[i]);
579 }
580 babai(float_matrix, gso.get_mu_matrix(), gso.get_r_matrix(), target, babai_sol);
581 int idx;
582 for (idx = 0; idx < d && babai_sol[idx] >= -1 && babai_sol[idx] <= 1; idx++)
583 {
584 }
585 if (idx == d)
586 break;
587
588 for (int i = 0; i < d; i++)
589 {
590 itmp1.set_f(babai_sol[i]);
591 sol_coord[i].add(sol_coord[i], itmp1);
592 for (int j = 0; j < n; j++)
593 int_new_target[j].submul(itmp1, b(i, j));
594 }
595 }
596 // FPLLL_TRACE("BabaiSol=" << sol_coord);
597 get_gscoords(float_matrix, gso.get_mu_matrix(), gso.get_r_matrix(), target, target_coord);
598
599 /* Computes a very large bound to make the algorithm work
600 until the first solution is found */
601 max_dist = 0.0;
602 for (int i = 1; i < d; i++)
603 {
604 // get_r_exp(i, i) = r(i, i) because gso is initialized without GSO_ROW_EXPO
605 max_dist.add(max_dist, gso.get_r_exp(i, i));
606 }
607
608 vector<int> max_indices;
609 if (method & CVPM_PROVED)
610 {
611 // For Exact CVP, we need to reset enum below depth with maximal r_i
612 max_indices = vector<int>(d);
613 int cur, max_index, previous_max_index;
614 previous_max_index = max_index = d - 1;
615 FP_NR<mpfr_t> max_val;
616
617 while (max_index > 0)
618 {
619 max_val = gso.get_r_exp(max_index, max_index);
620 for (cur = previous_max_index - 1; cur >= 0; --cur)
621 {
622 if (max_val <= gso.get_r_exp(cur, cur))
623 {
624 max_val = gso.get_r_exp(cur, cur);
625 max_index = cur;
626 }
627 }
628 for (cur = max_index; cur < previous_max_index; ++cur)
629 max_indices[cur] = max_index;
630 max_indices[previous_max_index] = previous_max_index;
631 previous_max_index = max_index;
632 --max_index;
633 }
634 }
635 FPLLL_TRACE("max_indices " << max_indices);
636
637 FastErrorBoundedEvaluator evaluator(n, gso.get_mu_matrix(), gso.get_r_matrix(), EVALMODE_CV);
638
639 // Main loop of the enumeration
640 Enumeration<Z_NR<mpz_t>, FP_NR<mpfr_t>> enumobj(gso, evaluator, max_indices);
641 enumobj.enumerate(0, d, max_dist, 0, target_coord);
642
643 int result = RED_ENUM_FAILURE;
644 if (!evaluator.empty())
645 {
646 FPLLL_TRACE("evaluator.bestsol_coord=" << evaluator.begin()->second);
647 if (flags & CVP_VERBOSE)
648 FPLLL_INFO("max_dist=" << max_dist);
649 for (int i = 0; i < d; i++)
650 {
651 itmp1.set_f(evaluator.begin()->second[i]);
652 sol_coord[i].add(sol_coord[i], itmp1);
653 }
654 result = RED_SUCCESS;
655 }
656
657 FP_NR<mpfr_t>::set_prec(old_prec);
658 return result;
659 }
660
661 FPLLL_END_NAMESPACE
662