Percy++
A C++ implementation of Private Information Retrieval (PIR) protocols
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Pages
rsdecoder_impl.h
1 // Percy++ Copyright 2007,2012,2013,2014
2 // Ian Goldberg <iang@cs.uwaterloo.ca>,
3 // Casey Devet <cjdevet@uwaterloo.ca>,
4 // Ann Yang <y242yang@uwaterloo.ca>,
5 // Paul Hendry <pshendry@uwaterloo.ca>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of version 2 of the GNU General Public License as
9 // published by the Free Software Foundation.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // There is a copy of the GNU General Public License in the COPYING file
17 // packaged with this plugin; if you cannot find it, write to the Free
18 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 // 02110-1301 USA
20 
21 #ifndef __GSDECODER_IMPL_H__
22 #define __GSDECODER_IMPL_H__
23 
24 #include <sstream>
25 #include <fstream>
26 #include <iostream>
27 #include <vector>
28 #include <map>
29 #include <set>
30 #include <algorithm>
31 #include <string>
32 #include <sys/time.h>
33 #include <time.h>
34 #include <NTL/vec_ZZ_p.h>
35 #include <NTL/ZZ_pXFactoring.h>
36 #include <NTL/GF2EXFactoring.h>
37 #include <NTL/mat_ZZ_p.h>
38 #include <NTL/mat_GF2E.h>
39 #include "subset.h"
40 #include "subset_iter.h"
41 #include "percyresult.h"
42 #include "FXY.h"
43 
44 // An implementation of the Guruswami-Sudan decoder. This decoder will
45 // produce all possible codewords of degree at most t that match the
46 // given codeword with k non-erasures in more than sqrt(k*t) places.
47 //
48 // It runs in polynomial time, but in the worst case, it's O(k^12).
49 // Luckily, the worst case is when t=k-2, which is easily solved by
50 // brute force. (You will need to do this brute force outside this
51 // class.)
52 //
53 // This implementation is based on the K\"otter and Roth-Ruckenstein
54 // algorithms, as described in: R. J. McEliece. The Guruswami-Sudan
55 // Decoding Algorithm for Reed-Solomon Codes. IPN Progress Report
56 // 42-153, May 15, 2003.
57 // http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
58 
59 // This file contains the (templated) implementations of the class
60 // methods.
61 
62 // Specializations for the derived types. Only vec_FX and
63 // vec_pair_FX_long are in here, because they're only used once. The
64 // rest of the derived types (vec_F, FX, FXY) are used many times, so
65 // it's more consice to make them explicit instead of having to write
66 // DT::vec_F every time.
67 template<>
68 struct RSDecoder_ZZ_p::DT {
69  typedef vec_ZZ_pX vec_FX;
70  typedef vec_pair_ZZ_pX_long vec_pair_FX_long;
71 };
72 
73 template<>
74 struct RSDecoder_GF2E::DT {
75  typedef vec_GF2EX vec_FX;
76  typedef vec_pair_GF2EX_long vec_pair_FX_long;
77 };
78 
79 // Set phi to the degree-t polynomial which interpolates the
80 // (indices,values) pairs indexed by I. Check which
81 // (indices,values) pairs indexed by G agree and disagree with
82 // phi, and set numagree, numdisagree, and vecagree accordingly.
83 template<class F, class vec_F, class FX, class FXY, class mat_F>
85  const vec_F &values, const vec_F &indices,
86  const vector<unsigned short> &I, const vector<unsigned short> &G,
87  unsigned short &numagree, unsigned short &numdisagree,
88  vector<unsigned short> &vecagree, FX &phi)
89 {
90  numagree = numdisagree = 0;
91 
92  // Use Lagrange interpolation to find the unique polynomial phi
93  // of degree t which matches the points indexed by I
94  vec_F I_indices, I_values;
95  I_indices.SetLength(t+1);
96  I_values.SetLength(t+1);
97  vector<unsigned short>::const_iterator Iiter;
98  unsigned short i = 0;
99  for (Iiter = I.begin(); Iiter != I.end(); ++i, ++Iiter) {
100  I_indices[i] = indices[*Iiter];
101  I_values[i] = values[*Iiter];
102  }
103  interpolate(phi, I_indices, I_values);
104 
105  // Count the number of points in G that agree, and that
106  // disagree, with phi
107  vector<unsigned short>::const_iterator Giter;
108  for (Giter = G.begin(); Giter != G.end(); ++Giter) {
109  F phival;
110  eval(phival, phi, indices[*Giter]);
111  if (phival == values[*Giter]) {
112  ++numagree;
113  vecagree.push_back(*Giter);
114  } else {
115  ++numdisagree;
116  }
117  }
118 }
119 
120 extern uint64_t hasseop;
121 
122 // Evaluate the (r,s)th Hasse mixed partial derivative of g at the point
123 // (alpha, beta), which is:
124 // \sum_{i,j} C(i,r) C(j,s) a_{i,j} alpha^{i-r} beta^{j-s}
125 // = \sum_j C(j,s) beta^{j-s} \sum_i C(i,r) a_{i,j} alpha^{i-r}
126 // where g(x,y) = \sum_{i,j} a_{i,j} x^i y^j
127 // See page 14 of R. J. McEliece. The Guruswami-Sudan Decoding
128 // Algorithm for Reed-Solomon Codes. IPN Progress Report 42-153, May 15,
129 // 2003. http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
130 template<class F, class vec_F, class FX, class FXY, class mat_F>
132  unsigned int r, unsigned int s,
133  F alpha, F beta, Ccache_t &Ccache)
134 {
135  F res;
136  res = 0;
137  int ydeg = deg(g);
138  for (int j = ydeg; j >= (int)s; --j) {
139  const FX &gj = coeff(g,j);
140  int xdeg = deg(gj);
141  // Use Horner's method to evaluate the inner sum (which is the
142  // coefficient of beta^{j-s})
143  F resx;
144  resx = 0;
145  for (int i = xdeg; i >= (int) r; --i) {
146  resx *= alpha;
147  resx += C(Ccache, i,r) * coeff(gj, i);
148  ++hasseop;
149  }
150  // Use Horner's method to accumulate the results into the outer
151  // sum
152  res *= beta;
153  res += C(Ccache, j,s) * resx;
154  ++hasseop;
155  }
156 
157  return res;
158 }
159 
160 extern uint64_t kotter_usec;
161 
162 // Construct a bivariate polynomial P(x,y) such that, for any polynomial
163 // f(x) of degree at most v that agrees with at least t of the given
164 // points, (y-f(x)) is a factor of P(x,y). This version is K"otter's
165 // Interpolation Algorithm, as described in Section VII of R. J.
166 // McEliece. The Guruswami-Sudan Decoding Algorithm for Reed-Solomon
167 // Codes. IPN Progress Report 42-153, May 15, 2003.
168 // http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
169 template<class F, class vec_F, class FX, class FXY, class mat_F>
171  unsigned int v, unsigned int t,
172  const vector<unsigned short> &goodservers,
173  const vec_F &indices, const vec_F &shares)
174 {
175  struct timeval st, et;
176  gettimeofday(&st, NULL);
177 
178  unsigned int n = goodservers.size();
179 
180  // Compute the m and L parameters
181  unsigned int m = 1 + (unsigned int)(floor( v*n / (t*t-v*n)));
182  unsigned int L = (m*t - 1)/v;
183 
184  if (getenv("PIRC_L")) {
185  L = atoi(getenv("PIRC_L"));
186  }
187  if (getenv("PIRC_m")) {
188  m = atoi(getenv("PIRC_m"));
189  }
190 
191  std::cerr << "Constructing (1," << v << ")-degree " << L*v << " polynomial...\n";
192  std::cerr << "Estimated work: " << n * m * (m+1) / 2 * (L+1) << "\n";
193  std::cerr << "L = " << L << "\n";
194  std::cerr << "m = " << m << "\n";
195  std::cerr << "Min matches: " << t << "\n";
196  std::cerr << "Max degree: " << v << "\n";
197 #if 0
198  double Km = v * n * (m+1);
199  Km /= (double) m;
200  Km = floor(sqrt(Km));
201  std::cerr << "Km ~= " << Km << "\n";
202  unsigned int C = n * m * (m+1) / 2;
203  for (int K=0;;++K) {
204  cerr << (K*(K+v)+(K%v)*(v-(K%v)))/(2*v) << " " << C << "\n";
205  if ( ((K*(K+v)+(K%v)*(v-(K%v)))/(2*v)) > C ) {
206  std::cerr << "Km: " << (K-1)/m + 1 << "\n";
207  break;
208  }
209  }
210 #endif
211 
212  // Initialize the g vector
213  typedef pair<FXY, unsigned int> polydeg;
214  polydeg * g = new polydeg[L+1];
215  for (unsigned int j = 0; j <= L; ++j) {
216  SetCoeff(g[j].first, j);
217  g[j].second = j * v;
218  }
219 
220  Ccache_t Ccache;
221 
222  F * Delta = new F[L+1];
223  for (unsigned int i = 0; i < n; ++i) {
224  F alpha = indices[goodservers[i]];
225  F beta = shares[goodservers[i]];
226  for (unsigned int r = 0; r < m; ++r) {
227  for (unsigned int s = 0; s < m - r; ++s) {
228  int seennonzero = 0;
229  unsigned int seendeg = 0, jstar = 0;
230  for (unsigned int j = 0; j <= L; ++j) {
231  Delta[j] = evalhasse(g[j].first, r, s, alpha, beta,
232  Ccache);
233  // cerr << i << " " << r << " " << s << " " << j;
234  if (Delta[j] != 0) {
235  // cerr << " nonzero";
236  seennonzero = 1;
237  seendeg = g[j].second;
238  jstar = j;
239  }
240  // cerr << "\n";
241  }
242  if (seennonzero) {
243  for (unsigned int j = 0; j <= L; ++j) {
244  if (Delta[j] != 0 && g[j].second <= seendeg) {
245  seendeg = g[j].second;
246  jstar = j;
247  }
248  }
249  F Deltajstar = Delta[jstar];
250  FXY f = g[jstar].first;
251  // cerr << "Deltajstar = " << Deltajstar << "\n";
252  // cerr << "f = " << f << "\n";
253  for (unsigned int j = 0; j <= L; ++j) {
254  if (Delta[j] != 0) {
255  if (j != jstar) {
256  // cerr << "g["<<j<<"] = " << Deltajstar << " * " << g[j].first << " - " << Delta[j] << " * " << f << " = ";
257 
258  g[j].first = Deltajstar * g[j].first -
259  Delta[j] * f;
260  // cerr << g[j].first << "\n";
261  } else {
262  FX xminusalpha;
263  SetCoeff(xminusalpha, 1, 1);
264  SetCoeff(xminusalpha, 0, -alpha);
265  // cerr << "g["<<j<<"] = " << Deltajstar << " * " << xminusalpha << " * " << f << " = ";
266  g[j].first = Deltajstar * xminusalpha * f;
267  // cerr << g[j].first << "\n";
268  g[j].second += 1;
269  }
270  }
271  // cerr << "Now -> " << evalhasse(g[j].first, r, s, alpha, beta, Ccache) << "\n";
272  }
273  }
274  }
275  }
276  }
277  delete[] Delta;
278 
279  // Return the poly of least weighted degree from g
280  unsigned int minweight = g[0].second;
281  unsigned int minindex = 0;
282  for (unsigned int i=1; i<=L; ++i) {
283  if (g[i].second <= minweight) {
284  minweight = g[i].second;
285  minindex = i;
286  }
287  }
288 
289  gettimeofday(&et, NULL);
290  kotter_usec = ((uint64_t)(et.tv_sec - st.tv_sec))*1000000
291  + (et.tv_usec - st.tv_usec);
292 
293  delete[] g;
294 
295  return g[minindex].first;
296 }
297 
298 // Construct a bivariate polynomial Q(x,y) such that, for any
299 // polynomial g(x) of degree at most ell that agrees with at least
300 // h of the given points, (y-g(x)) is a factor of Q(x,y). This
301 // version is Cohn and Heninger's improvement on the Guruswami-Sudan
302 // Decoding Algorithm as described in sections 1.2, 2.2 and 4 of
303 // Cohn, H. and Heninger, N. Ideal forms of Coppersmith's theorem and
304 // Guruswami-Sudan list decoding. August 6, 2010.
305 template<class F, class vec_F, class FX, class FXY, class mat_F>
307  unsigned int ell, unsigned int h,
308  const vector<unsigned short> &goodservers,
309  const vec_F &indices, const vec_F &shares)
310 {
311 #ifdef VERBOSE_CH
312  std::cerr << "STARTING COHN-HENINGER...\n";
313 #endif
314 
315  unsigned int n = goodservers.size();
316  unsigned int m = ((h - ell) * n) / (h * h - ell * n) + 1;
317  unsigned int k = (h * m) / n;
318  unsigned int t = m - k;
319 
320  unsigned int i, j;
321 
322  FX p;
323  SetCoeff(p, 0, 1);
324  for (i = 0; i < n; ++i) {
325  FX newTerm;
326  SetCoeff(newTerm, 0, -(indices[goodservers[i]]));
327  SetCoeff(newTerm, 1);
328  p *= newTerm;
329  }
330 
331  FX constCoeff;
332  for (i = 0; i < n; ++i) {
333  FX zPoly;
334  SetCoeff(zPoly, 0, 1);
335  for (j = 0; j < n; ++j) {
336  if (i == j) {
337  continue;
338  }
339  FX newTerm;
340  SetCoeff(newTerm, 0, -(indices[goodservers[j]]));
341  SetCoeff(newTerm, 1);
342  zPoly *= newTerm;
343  zPoly /= (indices[goodservers[i]] - indices[goodservers[j]]);
344  }
345  constCoeff += (zPoly * shares[goodservers[i]]);
346  }
347  FXY f;
348  SetCoeff(f, 1, 1);
349  SetCoeff(f, 0, -constCoeff);
350 
351 #ifdef VERBOSE_CH
352  std::cerr << "ell = " << ell << std::endl;
353  std::cerr << "h = " << h << std::endl;
354  std::cerr << "n = " << n << std::endl;
355  std::cerr << "m = " << m << std::endl;
356  std::cerr << "k = " << k << std::endl;
357  std::cerr << "t = " << t << std::endl;
358  std::cerr << "goodservers =";
359  for (i = 0; i < n; ++i) {
360  std::cerr << " " << goodservers[i];
361  }
362  std::cerr << std::endl;
363  std::cerr << "indices =";
364  for (i = 0; i < n; ++i) {
365  std::cerr << " " << indices[goodservers[i]];
366  }
367  std::cerr << std::endl;
368  std::cerr << "shares =";
369  for (i = 0; i < n; ++i) {
370  std::cerr << " " << shares[goodservers[i]];
371  }
372  std::cerr << std::endl;
373  std::cerr << "p(z) = " << p << std::endl;
374  std::cerr << "f(x) = " << f << std::endl;
375 #endif
376 
377  vector<FXY> basis; // Polynomials whose coefficient vectors are a lattice basis
378 
379  FX z_toell;
380  SetCoeff(z_toell, ell);
381  FXY z_toell_x;
382  SetCoeff(z_toell_x, 1, z_toell);
383  FXY f_of_z_toell_x = f;
384  SetCoeff(f_of_z_toell_x, 1, z_toell);
385 
386  vector<FXY> powers_of_f;
387  FXY one2;
388  SetCoeff(one2, 0, 1);
389  powers_of_f.push_back(one2);
390  powers_of_f.push_back(f_of_z_toell_x);
391  for (i = 2; i <= k; ++i) {
392  powers_of_f.push_back(powers_of_f.back() * f_of_z_toell_x);
393  }
394 
395  vector<FX> powers_of_p;
396  FX one1;
397  SetCoeff(one1, 0, 1);
398  powers_of_p.push_back(one1);
399  powers_of_p.push_back(p);
400  for (i = 2; i <= k; ++i) {
401  powers_of_p.push_back(powers_of_p.back() * p);
402  }
403 
404  for (i = 0; i <= k; ++i) {
405  FXY basis_poly = powers_of_f[i] * powers_of_p[k - i];
406  basis.push_back(basis_poly);
407  }
408 
409  char *opt_ch_env = getenv("PIRC_OPT_CH");
410  if (opt_ch_env && atoi(opt_ch_env)) {
411  // k+1-th basis vector (for if ell=n-2)
412  if (ell == n-2) {
413  FXY last_poly = basis[k] * z_toell_x;
414  basis.push_back(last_poly);
415  }
416 
417  } else {
418  FXY current_basis_poly = powers_of_f[k];
419  for (j = 1; j < t; ++j) {
420  current_basis_poly *= z_toell_x;
421  basis.push_back(current_basis_poly);
422  }
423  }
424 
425  vector<vector<FX> > lattice;
426  for (i = 0; i < m; ++i) {
427  vector<FX> row;
428  for (j = 0; j < m; ++j) {
429  row.push_back(coeff(basis[i], j));
430  }
431  lattice.push_back(row);
432  }
433 
434 
435 #ifdef VERBOSE_CH
436 
437  std::cerr << "ELEMENT DEGREES:\n";
438  for (i = 0; i < m; ++i) {
439  std::cerr << "\t";
440  for (j = 0; j < m; ++j) {
441  std::cerr << deg(lattice[i][j]) << "\t";
442  }
443  std::cerr << std::endl;
444  }
445 #endif
446 
447  vector<vector<FX> > aux (m, vector<FX>());
448  vector<vector<FX> > reducedLattice = reduce_lattice_MS(lattice, aux, k*h);
449  int mindeg = 0;
450  int minindex = -1;
451  for (i = 0; i < m; ++i) {
452  int maxdeg = -1;
453  for (j = 0; j < m; ++j) {
454  FX c = reducedLattice[i][j];
455  if (deg(c) >= maxdeg) {
456  maxdeg = deg(c);
457  }
458  }
459  if (minindex < 0 || maxdeg < mindeg) {
460  minindex = i;
461  mindeg = maxdeg;
462  }
463  }
464 // FXY Q = reducedBasis[minindex];
465  FXY Q;
466  for (i = 0; i < m; ++i) {
467  SetCoeff(Q, i, reducedLattice[minindex][i]);
468  }
469 
470 #ifdef VERBOSE_CH
471  std::cerr << "Q = [" << std::endl;
472  for (i = 0; i < m; ++i) {
473  FX c = coeff(Q, i);
474  std::cerr << " " << c << " (degree " << deg(c) + 1 << ")"
475  << std::endl;
476  }
477  std::cerr << " ]" << std::endl;
478 #endif
479 
480  FXY new_Q;
481  for (i = 0; i < m; ++i) {
482  SetCoeff(new_Q, i, RightShift(coeff(Q, i), i*ell));
483  }
484 
485 #ifdef VERBOSE_CH
486  std::cerr << "new_Q = [" << std::endl;
487  for (i = 0; i < m; ++i) {
488  FX c = coeff(new_Q, i);
489  std::cerr << " " << c << " (degree " << deg(c) + 1 << ")"
490  << std::endl;
491  }
492  std::cerr << " ]" << std::endl;
493 #endif
494 
495  return new_Q;
496 }
497 
498 // Perform lattice basis reduction on a lattice with m basis vectors in F[z].
499 // The lattice is represented by a vector 'lattice' in (F[z][x])^m such that
500 // the coefficient vectors of each element in 'lattice' is a basis for the
501 // lattice. If set, the algorithm stops after finding reduceNumber rows
502 // of degree less than reduceTo. This implementation uses the
503 // algorithm found in Mulders, T. and Storjohann, A. On Lattice Reduction for
504 // Polynomial Matrices. December 2000.
505 template<class F, class vec_F, class FX, class FXY, class mat_F>
506 vector<vector<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::reduce_lattice_MS(vector<vector<FX> > lattice,
507  // The auxiliary matrix must have the same number of rows as lattice
508  // If not, no operations will be performed on aux.
509  vector<vector<FX> >& aux,
510  const int reduceTo, const unsigned int reduceNumber)
511 {
512 
513  // Keep track of number of rows with small enough degree
514  map<unsigned int, bool> small_rows;
515 
516  // Keeps track of pivot information (row, degree and leading coefficient)
517  // for a particular column of a lattice matrix.
518  struct PivotInfo {
519  bool used;
520  unsigned int row;
521  unsigned int degree;
522  F lc;
523 
524  PivotInfo () {
525  used = false;
526  row = 0;
527  degree = 0;
528  lc = 0;
529  }
530  };
531 
532  unsigned int m = lattice.size();
533 
534  bool use_aux = aux.size() == m && aux[0].size() > 0;
535 
536  // Create the pivots array
537  PivotInfo * pivots = new PivotInfo[m];
538 
539  for (unsigned int row = 0; row < m; ++row) {
540  unsigned int workrow = row;
541  // Find pivot
542  unsigned int pIndex = 0;
543  unsigned int degree = deg(lattice[workrow][0]) + 1;
544  for (unsigned int i = 0; i < m; ++i) {
545  if ((unsigned int)(deg(lattice[workrow][i]) + 1) >= degree) {
546  pIndex = i;
547  degree = deg(lattice[workrow][i]) + 1; // Use +1 to avoid -1 degree
548  }
549  }
550  F lc = LeadCoeff(lattice[workrow][pIndex]);
551 
552  // Check if we can stop
553  if (reduceTo >= 0 && degree <= (unsigned int)reduceTo) {
554  small_rows[workrow] = true;
555  }
556  if (small_rows.size() >= reduceNumber) {
557  delete[] pivots;
558  return lattice;
559  }
560 
561 #ifdef VERBOSE_MS
562  std::cerr << "Element Degrees:" << std::endl;
563  for (unsigned int i = 0; i < m; ++i) {
564  std::cerr << "\t";
565  for (unsigned int j = 0; j < m; ++j) {
566  std::cerr << deg(lattice[i][j]) + 1 << "\t";
567  }
568  std::cerr << std::endl;
569  }
570  std::cerr << "Pivot Info:" << std::endl;
571  for (unsigned int i = 0; i < m; ++i) {
572  std::cerr << "pivot[" << i << "]:\tused = " << pivots[i].used
573  << "\trow = " << pivots[i].row << "\tdegree = "
574  << pivots[i].degree << "\tlc = " << pivots[i].lc << std::endl;
575  }
576  std::cerr << "workrow = " << workrow << std::endl;
577  std::cerr << "pIndex = " << pIndex << std::endl;
578  std::cerr << "degree = " << degree << std::endl;
579  std::cerr << "lc = " << lc << std::endl;
580 #endif
581 
582  while (pivots[pIndex].used) {
583  if (degree < pivots[pIndex].degree) {
584  // Swap current pivot with pivots[pIndex]
585  unsigned int tmp_workrow = workrow;
586  unsigned int tmp_degree = degree;
587  F tmp_lc = lc;
588  workrow = pivots[pIndex].row;
589  degree = pivots[pIndex].degree;
590  lc = pivots[pIndex].lc;
591  pivots[pIndex].row = tmp_workrow;
592  pivots[pIndex].degree = tmp_degree;
593  pivots[pIndex].lc = tmp_lc;
594  }
595 
596  // Perform the tranformation
597  FX transConst (degree - pivots[pIndex].degree, lc / pivots[pIndex].lc);
598  for (unsigned int i = 0; i < m; ++i) {
599  lattice[workrow][i] -= lattice[pivots[pIndex].row][i] * transConst;
600  }
601  if (use_aux) {
602  for (unsigned int i = 0; i < aux[0].size(); ++i) {
603  aux[workrow][i] -= aux[pivots[pIndex].row][i] * transConst;
604  }
605  }
606 
607  // Find new pivot
608  pIndex = 0;
609  degree = deg(lattice[workrow][0]) + 1;
610  for (unsigned int i = 1; i < m; ++i) {
611  if ((unsigned int)(deg(lattice[workrow][i]) + 1) >= degree) {
612  pIndex = i;
613  degree = deg(lattice[workrow][i]) + 1; // Use +1 to avoid -1 degree
614  }
615  }
616  lc = LeadCoeff(lattice[workrow][pIndex]);
617 
618  // Check if we can stop
619  if (reduceTo >= 0 && degree <= (unsigned int)reduceTo) {
620  small_rows[workrow] = true;
621  }
622  if (small_rows.size() >= reduceNumber) {
623  delete[] pivots;
624  return lattice;
625  }
626 
627 #ifdef VERBOSE_MS
628  std::cerr << "Element Degrees:" << std::endl;
629  for (unsigned int i = 0; i < m; ++i) {
630  std::cerr << "\t";
631  for (unsigned int j = 0; j < m; ++j) {
632  std::cerr << deg(lattice[i][j]) + 1 << "\t";
633  }
634  std::cerr << std::endl;
635  }
636  std::cerr << "Pivot Info:" << std::endl;
637  for (unsigned int i = 0; i < m; ++i) {
638  std::cerr << "pivot[" << i << "]:\tused = " << pivots[i].used
639  << "\trow = " << pivots[i].row << "\tdegree = "
640  << pivots[i].degree << "\tlc = " << pivots[i].lc << std::endl;
641  }
642  std::cerr << "workrow = " << workrow << std::endl;
643  std::cerr << "pIndex = " << pIndex << std::endl;
644  std::cerr << "degree = " << degree << std::endl;
645  std::cerr << "lc = " << lc << std::endl;
646 #endif
647  }
648  // Add PivotInfo to pivots
649  pivots[pIndex].used = true;
650  pivots[pIndex].row = workrow;
651  pivots[pIndex].degree = degree;
652  pivots[pIndex].lc = lc;
653  }
654 
655 #ifdef VERBOSE_MS
656  std::cerr << "Element Degrees:" << std::endl;
657  for (unsigned int i = 0; i < m; ++i) {
658  std::cerr << "\t";
659  for (unsigned int j = 0; j < m; ++j) {
660  std::cerr << deg(lattice[i][j]) + 1 << "\t";
661  }
662  std::cerr << std::endl;
663  }
664  std::cerr << "Pivot Info:" << std::endl;
665  for (unsigned int i = 0; i < m; ++i) {
666  std::cerr << "pivot[" << i << "]:\tused = " << pivots[i].used
667  << "\trow = " << pivots[i].row << "\tdegree = "
668  << pivots[i].degree << "\tlc = " << pivots[i].lc << std::endl;
669  }
670 #endif
671 
672  delete[] pivots;
673  return lattice;
674 }
675 
676 // Find all polynomials of degree at most k that agree with the given
677 // (index,share) pairs at at least t of the n points. The notation is
678 // from Venkatesan Guruswami and Madhu Sudan, "Improved Decoding of
679 // Reed-Solomon and Algebraic-Geometry Codes".
680 template<class F, class vec_F, class FX, class FXY, class mat_F>
681 vector< RecoveryPoly<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_gs(unsigned int k,
682  unsigned int t, const vector<unsigned short> &goodservers,
683  const vec_F &indices, const vec_F &shares, TestType testType)
684 {
685  FXY P;
686 
687  // Check that method is KOTTER or CH_MS
688  switch (testType) {
689  case KOTTER:
690  P = interpolate_kotter(k, t, goodservers, indices, shares);
691  break;
692  case CH_MS:
693  P = interpolate_cohn_heninger(k, t, goodservers, indices, shares);
694  break;
695  default:
696  std::cerr << "ERROR: Invalid test method for findpolys().\n";
697  return vector<RecoveryPoly<FX> >(); // Fail
698  }
699 
700 #if 0
701  // cerr << "factor(poly(0";
702  for(int j=0;j<=deg(P);++j) {
703  FX x = coeff(P,j);
704  for(int i=0; i<=deg(x); ++i) {
705  // cerr << " + " << coeff(x,i) << "*x^" << i << "*y^" << j;
706  }
707  }
708 #endif
709  // cerr << ", [x,y], IntMod(" << p1*p2 << ")));\n\n";
710  std::cerr << "Finding roots of resulting polynomial...\n";
711 
712  // It turns out that any polynomial phi(x) that we should be
713  // returning (since phi is of degree at most k and agrees with the
714  // input data on at least t points) is such that (y - phi(x)) is a
715  // factor of P(x,y). So we first find all roots for y of P(x,y)
716  // which are polynomials of degree at most k.
717  vector<FX> roots = findroots(P, k);
718  // cerr << "roots = " << roots << "\n";
719 
720  // For each of these roots, check how many input points it agrees
721  // with. If it's at least t, add it to the list of polys to return.
722  vector< RecoveryPoly<FX> > polys;
723  unsigned int numroots = roots.size();
724  for (unsigned int i=0; i<numroots; ++i) {
725  if (deg(roots[i]) > (long)k) continue;
726  vector<unsigned short>::const_iterator gooditer;
727  vector<unsigned short> vecagree;
728  unsigned short numagree = 0;
729  for (gooditer = goodservers.begin(); gooditer != goodservers.end();
730  ++gooditer) {
731  F phival;
732  eval(phival, roots[i], indices[*gooditer]);
733  if (phival == shares[*gooditer]) {
734  ++numagree;
735  vecagree.push_back(*gooditer);
736  }
737  }
738  if (numagree >= t) {
739  RecoveryPoly<FX> n(vecagree, roots[i]);
740  polys.push_back(n);
741  }
742  }
743 
744  return polys;
745 }
746 
747 // Find all polynomials of degree at most k that agree with the given
748 // (index,share) pairs at at least t of the n points. This version
749 // simply uses brute force and interpolates all subsets of size k+1 of
750 // the n points. Note that in general, this version does *not* run in
751 // polynomial time, but for some cases (with n-k small, for example) it
752 // is faster than Guruswami-Sudan.
753 //
754 // Runtime is about C(k,t+1) *
755 // [2.55712398139188+1.17564033117597*k+4.20999565858028*t+1.21270558067138*t^2]
756 // microseconds, according to observations and regression analysis.
757 template<class F, class vec_F, class FX, class FXY, class mat_F>
758 vector<RecoveryPoly<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_brute(
759  int k_signed, unsigned int t,
760  const vector<unsigned short> &goodservers,
761  const vec_F &indices, const vec_F &shares)
762 {
763  //std::cerr << "RUNNING BRUTE\n";
764 
765  if (k_signed < -1) {
766  return vector<RecoveryPoly<FX> >(); // Fail
767  }
768 
769  // k == -1
770  if (k_signed == -1) {
771  // Check if at least h shares are zero
772  vector<unsigned short>::const_iterator gooditer;
773  vector<unsigned short> vecagree;
774  unsigned short numagree = 0;
775  for (gooditer = goodservers.begin(); gooditer != goodservers.end();
776  ++gooditer) {
777  if (F::zero() == shares[*gooditer]) {
778  ++numagree;
779  vecagree.push_back(*gooditer);
780  }
781  }
782  if (numagree >= t) {
783  return vector< RecoveryPoly<FX> >(1, RecoveryPoly<FX>(vecagree, FX::zero()));
784  } else {
785  return vector< RecoveryPoly<FX> >(); // Fail
786  }
787  }
788 
789  //std::cerr << "CHECK 1\n";
790 
791  // k >= 0
792  unsigned int k = (unsigned int)k_signed;
793  vector<RecoveryPoly<FX> > polys;
794 
795 unsigned int numcombs = 0;
796  // Iterate over all subsets of goodservers of size k+1
797  subset_iterator iter(goodservers, k+1);
798 
799  //std::cerr << "CHECK 2\n";
800 
801  while(!iter.atend()) {
802  ++numcombs;
803 
804  //std::cerr << "CHECK 2 a\n";
805 
806  unsigned short numagree, numdisagree;
807  vector<unsigned short> vecagree;
808  FX phi;
809 
810  // We should probably avoid calling this if polys[i].G is a
811  // superset of *iter for some i, but "is a superset" is a
812  // non-trivial test with the current data structure, so we'll
813  // just run it anyway for now, and check for uniqueness of phi
814  // on the way out.
815  test_interpolate(k, shares, indices, *iter, goodservers,
816  numagree, numdisagree, vecagree, phi);
817 
818  //std::cerr << "CHECK 2 b\n";
819 
820  if (numagree >= t) {
821  // As above: check to see if we've seen this phi before
822  typename vector<RecoveryPoly<FX> >::iterator polysiter;
823  bool matched = false;
824  for (polysiter = polys.begin(); polysiter != polys.end();
825  ++polysiter) {
826  if (polysiter->phi == phi) {
827  matched = true;
828  break;
829  }
830  }
831  if (!matched) {
832  RecoveryPoly<FX> n(vecagree, phi);
833  polys.push_back(n);
834  }
835  // See if this is the only possible solution. If so, stop
836  if (t > k + numdisagree) {
837  break;
838  }
839  }
840 
841  //std::cerr << "CHECK 2 c\n";
842 
843  ++iter;
844  }
845 
846  //std::cerr << "CHECK 3\n";
847 
848  return polys;
849 }
850 
851 // Find a polynomial of degree ell that agrees with at least h shares. Uses
852 // the Berlekamp-Welch algorithm. This algorithm is only guaranteed to work
853 // when 2h > n + ell.
854 template<class F, class vec_F, class FX, class FXY, class mat_F>
855 vector<RecoveryPoly<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_bw(
856  unsigned int ell, unsigned int h,
857  const vector<unsigned short> &goodservers,
858  const vec_F &indices, const vec_F &shares)
859 {
860  unsigned int n = goodservers.size();
861  unsigned int numcols = n + n - h - h + ell + 2;
862  mat_F M(INIT_SIZE, n, numcols);
863 
864  for (unsigned int i = 0; i < n; ++i) {
865  F multiplier = indices[goodservers[i]];
866  M[i][0] = 1;
867  for (unsigned int j = 1; j <= n - h + ell; ++j) {
868  M[i][j] = M[i][j-1] * multiplier;
869  }
870  M[i][n-h+ell+1] = -(shares[goodservers[i]]);
871  for (unsigned int j = n - h + ell + 2; j < numcols; ++j) {
872  M[i][j] = M[i][j-1] * multiplier;
873  }
874  }
875 
876 #ifdef VERBOSE_BW
877  std::cerr << "n = " << n << std::endl;
878  std::cerr << "ell = " << ell << std::endl;
879  std::cerr << "h = " << h << std::endl;
880  std::cerr << "indices =";
881  for (unsigned int i = 0; i < n; ++i) {
882  std::cerr << " " << indices[goodservers[i]];
883  }
884  std::cerr << std::endl;
885  std::cerr << "shares =";
886  for (unsigned int i = 0; i < n; ++i) {
887  std::cerr << " " << shares[goodservers[i]];
888  }
889  std::cerr << std::endl;
890  std::cerr << "numcols = " << numcols << std::endl;
891  std::cerr << "M = " << M << std::endl;
892 #endif
893 
894  unsigned int rank = gauss(M);
895 
896 #ifdef VERBOSE_BW
897  std::cerr << "rank = " << rank << std::endl;
898  std::cerr << "reduced M = " << M << std::endl;
899 #endif
900 
901  if (rank == numcols) {
902 #ifdef VERBOSE_BW
903  std::cerr << "FAIL: y_i*E(x_i)=Q)x_i) has no solution" << std::endl;
904 #endif
905  return vector<RecoveryPoly<FX> >();
906  }
907 
908  unsigned int findex;
909  for (findex = 0; findex < n; ++findex) {
910  if (IsZero(M[findex][findex])) {
911  break;
912  }
913  }
914 
915 #ifdef VERBOSE_BW
916  std::cerr << "findex = " << findex << std::endl;
917 #endif
918 
919  vec_F coeffs(INIT_SIZE, numcols);
920  coeffs[findex] = 1;
921  for (unsigned int i = findex; i > 0; ) {
922  --i; // To avoid checking that an unsigned int is >=0
923  F c;
924  for (unsigned int j = i + 1; j <= findex; ++j) {
925  c -= M[i][j] * coeffs[j];
926  }
927  c /= M[i][i];
928  coeffs[i] = c;
929  }
930 
931 #ifdef VERBOSE_BW
932  std::cerr << "coeffs:" << std::endl;
933  for (unsigned int i = 0; i < numcols; ++i) {
934  std::cerr << "\t" << i << "\t" << coeffs[i] << std::endl;
935  }
936 #endif
937 
938  FX Q, E;
939  for (unsigned int i = 0; i <= n - h + ell; ++i) {
940  SetCoeff(Q, i, coeffs[i]);
941  }
942  for (unsigned int i = 0; i <= n - h; ++i) {
943  SetCoeff(E, i, coeffs[n - h + ell + 1 + i]);
944  }
945 
946 #ifdef VERBOSE_BW
947  std::cerr << "Q = " << Q << std::endl;
948  std::cerr << "E = " << E << std::endl;
949 
950  // Check that y_i*E(x_i)=Q(x_i)
951  for (unsigned int i = 0; i < n; ++i) {
952  if (shares[goodservers[i]] * eval(E, indices[goodservers[i]]) != eval(Q, indices[goodservers[i]])) {
953  std::cerr << "ERROR: check failed for i = " << i << std::endl;
954  }
955  }
956 #endif
957 
958  FX result;
959  if (!divide(result, Q, E)) {
960 #ifdef VERBOSE_BW
961  std::cerr << "FAIL: Q % E != 0" << std::endl;
962 #endif
963  return vector<RecoveryPoly<FX> >();
964  }
965 
966  if (deg(result) > 0 && ((unsigned int)deg(result)) > ell) {
967 #ifdef VERBOSE_BW
968  std::cerr << "FAIL: deg(result) > " << ell << std::endl;
969 #endif
970  return vector<RecoveryPoly<FX> >();
971  }
972 
973 #ifdef VERBOSE_BW
974  std::cerr << "result = " << result << std::endl;
975 #endif
976 
977  // For result, check how many input points it agrees
978  // with. If it's at least t, add it to the list of polys to return.
979  vector< RecoveryPoly<FX> > polys;
980  vector<unsigned short>::const_iterator gooditer;
981  vector<unsigned short> vecagree;
982  unsigned short numagree = 0;
983  for (gooditer = goodservers.begin(); gooditer != goodservers.end();
984  ++gooditer) {
985  F phival;
986  eval(phival, result, indices[*gooditer]);
987  if (phival == shares[*gooditer]) {
988  ++numagree;
989  vecagree.push_back(*gooditer);
990  }
991  }
992  if (numagree >= h && 2*numagree > n+ell) {
993  RecoveryPoly<FX> n(vecagree, result);
994  polys.push_back(n);
995  }
996 
997  return polys;
998 }
999 
1000 /*
1001 // Gaussian elimination of a matrix over FX. Result leaves matrix in row
1002 // echelon form. This method is in-place (changes the given matrix). The rank
1003 // of the matrix is returned.
1004 template<class F, class vec_F, class FX, class FXY, class mat_F>
1005 int gaussian_FX (vector<vector<FX> >& A, vector<FX>& b) {
1006  vector<vector<FX> > mat = matrix;
1007  std::cerr << "CHECKPOINT 2a\n";
1008  unsigned n = mat.size();
1009  std::cerr << "CHECKPOINT 2b\n";
1010  unsigned m = mat[0].size();
1011  std::cerr << "CHECKPOINT 2c\n";
1012  unsigned int h = 0;
1013  std::cerr << "CHECKPOINT 2d\n";
1014  for (unsigned int i = 0; i < n && h < m; ++i) {
1015  std::cerr << "CHECKPOINT 2d 1\n";
1016  FX elem_ih = mat[i][h];
1017  // Find pivot
1018  std::cerr << "CHECKPOINT 2d 2\n";
1019  while (IsZero(elem_ih)) {
1020  if (h == m) {
1021  return mat;
1022  }
1023  unsigned int j;
1024  for (j = i + 1; j < n; ++j) {
1025  if (!IsZero(mat[j][h])) {
1026  vector<FX> tmp = mat[j];
1027  mat[j] = mat[i];
1028  mat[i] = tmp;
1029  break;
1030  }
1031  }
1032  if (j == n) {
1033  ++h;
1034  }
1035  elem_ih = mat[i][h];
1036  }
1037  std::cerr << "CHECKPOINT 2d 3\n";
1038  for (unsigned int j = i + 1; j < n; ++j) {
1039  FX elem_jh = mat[j][h];
1040  if (elem_jh != 0) {
1041  // (Row j) <- (Row j) * M_ih / gcd(M_ih, M_jh) - (Row i) * M_jh / gcd(M_ih, M_jh)
1042  FX gcd = GCD(elem_ih, elem_jh);
1043  for (unsigned int k = h; k < m; ++k) {
1044  mat[j][k] = mat[j][k] * (elem_ih / gcd) - mat[i][k] * (elem_jh / gcd);
1045  }
1046  }
1047  elem_ih = mat[i][h];
1048  }
1049  std::cerr << "CHECKPOINT 2d 4\n";
1050  ++h;
1051  }
1052  return mat;
1053 }
1054 */
1055 
1056 // Solve the linear system of equations Ax=b.
1057 template<class F, class vec_F, class FX, class FXY, class mat_F>
1059  vector<vector<FX> >& A, vector<FX>& b, unsigned int modulus) {
1060 
1061  // Sanity checks
1062  unsigned int n = A.size(); // Number of rows
1063  if (n == 0) {
1064  std::cerr << "FAIL: invalid_linsys: A is empty\n";
1065  return vector<FX>(); // Fail
1066  }
1067  unsigned int m = A[0].size(); // Number of cols
1068  if (b.size() != n) {
1069  std::cerr << "FAIL: invalid_linsys: Size of b does not match dimensions of A\n";
1070  return vector<FX>(); // Fail
1071  }
1072 
1073  std::vector<unsigned int> freeCols;
1074  unsigned int h = 0;
1075  for (unsigned int i = 0; i < n && h < m; ++i) {
1076  while (IsZero(A[i][h])) {
1077  //std::cerr << "(i, h) = (" << i << ", " << h << ")\n";
1078  // Find pivot for column h and put it in row i
1079  unsigned int j;
1080  for (j = i+1; j < n; ++j) {
1081  if (!IsZero(A[j][h])) {
1082  // Swap rows i and j
1083  vector<FX> tmp_row = A[i];
1084  A[i] = A[j];
1085  A[j] = tmp_row;
1086  FX tmp_elem = b[i];
1087  b[i] = b[j];
1088  b[j] = tmp_elem;
1089  break;
1090  }
1091  }
1092 
1093  // Did we find a pivot?
1094  if (j == n) {
1095  freeCols.push_back(h);
1096  ++h;
1097  // What if h == m now?
1098  if (h == m) {
1099  goto done_upper_triangular;
1100  }
1101  }
1102  }
1103 
1104  // Do row operations
1105  for (unsigned int j = i+1; j < n; ++j) {
1106  if (!IsZero(A[j][h])) {
1107  // (Row j) <-- (Row j) * A_ih / gcd(A_ih, Ajh)
1108  // - (Row i) * A_jh / gcd(A_ih, A_jh)
1109  FX gcd = GCD(A[i][h], A[j][h]);
1110  FX mult1 = A[i][h] / gcd;
1111  FX mult2 = A[j][h] / gcd;
1112  if (modulus > 0) {
1113  for (unsigned int k = h; k < m; ++k) {
1114  A[j][k] = MulTrunc(A[j][k], mult1, modulus)
1115  - MulTrunc(A[i][k], mult2, modulus);
1116  }
1117  b[j] = MulTrunc(b[j], mult1, modulus)
1118  - MulTrunc(b[i], mult2, modulus);
1119  } else {
1120  for (unsigned int k = h; k < m; ++k) {
1121  A[j][k] = (A[j][k] * mult1) - (A[i][k] * mult2);
1122  }
1123  b[j] = (b[j] * mult1) - (b[i] * mult2);
1124  }
1125  }
1126  }
1127  ++h;
1128  }
1129 
1130 done_upper_triangular:
1131  //std::cerr << "A | b =\n";
1132  //for (unsigned int i = 0; i < n; ++i) {
1133  // std::cerr << "\t";
1134  // for (unsigned int j = 0; j < n; ++j) {
1135  // std::cerr << deg(A[i][j]) << "\t";
1136  // }
1137  // std::cerr << "|\t" << b[i] << "\n";
1138  //}
1139  //std::cerr << "freeCols = { ";
1140  //for (unsigned int i = 0; i < freeCols.size(); ++i) {
1141  // std::cerr << freeCols[i] << " ";
1142  //}
1143  //std::cerr << "}\n";
1144 
1145  // Check that there is a solution (consistency)
1146  unsigned int rank = n - freeCols.size();
1147  for (unsigned int i = rank; i < n; ++i) {
1148  if (!IsZero(b[i])) {
1149  std::cerr << "FAIL: no_solution: inconsistent matrix\n";
1150  return vector<FX>(); // Fail
1151  }
1152  }
1153 
1154  // Get solution (free variables have value zero)
1155  vector<FX> solution (m, FX::zero());
1156  unsigned int sub = freeCols.size();
1157  for (unsigned int i = m; i > 0;) {
1158  --i;
1159  if (sub > 0 && freeCols[sub-1] == i) {
1160  --sub;
1161  } else {
1162  solution[i] = b[i-sub];
1163  for (unsigned int j = i+1; j < m; ++j) {
1164  solution[i] -= A[i-sub][j] * solution[j];
1165  }
1166  solution[i] = solution[i] / A[i-sub][i];
1167  }
1168  }
1169 
1170  //std::cerr << "solution =\n";
1171  //for (unsigned int i = 0; i < solution.size(); ++i) {
1172  // std::cerr << "\t" << solution[i] << "\n";
1173  //}
1174 
1175  return solution;
1176 }
1177 
1178 #ifdef INCLUDE_GENERAL_MULTI
1179 template<class F, class vec_F, class FX, class FXY, class mat_F>
1180 vector<map<unsigned int, FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::solve_partial_solution (
1181  unsigned int ell, unsigned int h, map<unsigned int, FX> partial,
1182  const vector<vector<FX> >& rows, vector<unsigned int> row_order,
1183  const vector<vector<unsigned int> >& order_of_expts)
1184 {
1185 // std::cerr << "solving partial: ";
1186 // typename map<unsigned int, FX>::iterator it;
1187 // for (it = partial.begin(); it != partial.end(); ++it) {
1188 // std::cerr << "x" << it->first << " = " << it->second << ", ";
1189 // }
1190 // std::cerr << "\n";
1191 
1192  unsigned int dim = order_of_expts.size();
1193  if (dim == 0) {
1194 #ifdef VERBOSE_CH_MULTI
1195  std::cerr << "FAIL: order_of_expts is empty\n";
1196 #endif
1197  return vector<map<unsigned int, FX> >(); // Fail
1198  }
1199  unsigned int m = order_of_expts[0].size();
1200 
1201  // Have a solution. Check that it is consistent.
1202  if (partial.size() == m) {
1203 // std::cerr << "** BASE **\n";
1204  for (unsigned int i = 0; i < row_order.size(); ++i) {
1205  vector<FX> row = rows[row_order[i]];
1206  FX cterm;
1207  for (unsigned int j = 0; j < dim; ++j) {
1208  if (IsZero(row[j])) {
1209  continue;
1210  }
1211  FX current = row[j];
1212  vector<unsigned int> expts = order_of_expts[j];
1213  for (unsigned int p = 0; p < m; ++p) {
1214  current *= power(partial[p], expts[p]);
1215  }
1216  cterm += current;
1217  }
1218 // std::cerr << "cterm = " << cterm << "\n";
1219  if (!IsZero(cterm)) {
1220  return vector<map<unsigned int, FX> >(); // Not a solution.
1221  }
1222  }
1223  return vector<map<unsigned int, FX> >(1, partial);
1224  }
1225 
1226  // Solve another variable.
1227  for (unsigned int i = 0; i < row_order.size(); ++i) {
1228 // std::cerr << "i = " << i << "\n";
1229  vector<FX> row = rows[row_order[i]];
1230  // See if row with partial solution is in F[z][xi] for some i
1231  FXY tosolve;
1232  unsigned int tosolve_var = 0;
1233  bool has_tosolve_var = false;
1234  bool too_many_vars = false;
1235  for (unsigned int j = 0; j < dim; ++j) {
1236 // std::cerr << "j = " << j << "\n";
1237  if (IsZero(row[j])) {
1238  continue;
1239  }
1240  vector<unsigned int> expts = order_of_expts[j];
1241  FX coeff = row[j];
1242  for (unsigned int p = 0; p < m; ++p) {
1243 // std::cerr << "p = " << p << "\n";
1244  if (expts[p] == 0) {
1245  continue;
1246  }
1247  typename map<unsigned int, FX>::iterator partialIter = partial.find(p);
1248  if (partialIter == partial.end()) {
1249  // Unknown variable
1250  if (has_tosolve_var && tosolve_var != p) {
1251  too_many_vars = true;
1252  break;
1253  }
1254  has_tosolve_var = true;
1255  tosolve_var = p;
1256  } else {
1257  coeff *= power(partialIter->second, expts[p]);
1258  }
1259  }
1260  if (too_many_vars) {
1261  break;
1262  }
1263  if (has_tosolve_var) {
1264  tosolve += FXY(expts[tosolve_var], coeff);
1265  } else {
1266  tosolve += FXY(0, coeff);
1267  }
1268  if (tosolve == 0) {
1269  // Row equals zero
1270  has_tosolve_var = false;
1271  }
1272  }
1273 //#ifdef VERBOSE_CH_MULTI
1274 // std::cerr << "row # = " << row_order[i] << "\n";
1275 //#endif
1276  if (too_many_vars) {
1277  continue;
1278  }
1279 //#ifdef VERBOSE_CH_MULTI
1280 // std::cerr << "tosolve = " << tosolve << "\n";
1281 //#endif
1282  row_order.erase(row_order.begin() + i);
1283  if (!has_tosolve_var) {
1284  // No unknowns
1285  if (!IsZero(tosolve)) {
1286  return vector<map<unsigned int, FX> >(); // Not a solution.
1287  }
1288  --i;
1289  continue;
1290  }
1291  // Can solve
1292  vector<FX> roots = findroots(tosolve, ell);
1293 //#ifdef VERBOSE_CH_MULTI
1294 // std::cerr << "roots =";
1295 // for (unsigned int j = 0; j < roots.size(); ++j) {
1296 // std::cerr << " " << roots[j];
1297 // }
1298 // std::cerr << "\n";
1299 //#endif
1300  vector<map<unsigned int, FX> > result;
1301  for (unsigned int j = 0; j < roots.size(); ++j) {
1302  partial[tosolve_var] = roots[j];
1303  vector<map<unsigned int, FX> > root_result =
1304  solve_partial_solution(ell, h, partial, rows, row_order, order_of_expts);
1305  result.insert(result.end(), root_result.begin(), root_result.end());
1306  }
1307  return result;
1308  }
1309  if (partial.size() > 0) {
1310  return vector<map<unsigned int, FX> >(1, partial); // Return partial solution
1311  }
1312  return vector<map<unsigned int, FX> >(); // No vars could be solved
1313 }
1314 
1315 template<class F, class vec_F, class FX, class FXY, class mat_F>
1316 vector<RecoveryPolyMulti<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_ch_multi(
1317  unsigned int ell, unsigned int h, unsigned int m, unsigned int& t,
1318  unsigned int& k,
1319  const vector<unsigned short> &goodservers,
1320  const vec_F &indices, const vector<vec_F> &shares) {
1321 
1322 #ifdef VERBOSE_CH_MULTI
1323  std::cerr << "Starting Cohn-Heninger Multi-Polynomial algorithm...\n";
1324 #endif
1325 
1326  unsigned int n = goodservers.size();
1327  unsigned int dim = 1;
1328  for (unsigned int i = 0; i < (m<t?m:t); ++i) {
1329  dim *= (m + t - i);
1330  dim /= (i + 1);
1331  }
1332 
1333 #ifdef VERBOSE_CH_MULTI
1334  std::cerr << "n = " << n << "\n";
1335  std::cerr << "ell = " << ell << "\n";
1336  std::cerr << "h = " << h << "\n";
1337  std::cerr << "m = " << m << "\n";
1338  std::cerr << "t = " << t << "\n";
1339  std::cerr << "k = " << k << "\n";
1340  std::cerr << "dim = " << dim << "\n";
1341 #endif
1342 
1343 #ifdef TIME_PARTS
1344  std::stringstream tsout;
1345  tsout << n << "," << ell << "," << h << ",";
1346 #endif
1347 
1348  // Create N(z)
1349  FX N;
1350  SetCoeff(N, 0, 1);
1351  for (unsigned int i = 0; i < n; ++i) {
1352  FX newTerm;
1353  SetCoeff(newTerm, 0, -(indices[goodservers[i]]));
1354  SetCoeff(newTerm, 1);
1355  N *= newTerm;
1356  }
1357 
1358 #ifdef VERBOSE_CH_MULTI
1359  std::cerr << "N(z) = " << N << " (" << deg(N) << ")\n";
1360 #endif
1361 
1362  // Create L[i](z), the interpolation of points in shares[i]
1363  vector<FX> L;
1364  vec_F goodIndices(INIT_SIZE, n);
1365  for (unsigned int j = 0; j < n; ++j) {
1366  goodIndices[j] = indices[goodservers[j]];
1367  }
1368  for (unsigned int i = 0; i < m; ++i) {
1369  vec_F goodShares(INIT_SIZE, n);
1370  for (unsigned int j = 0; j < n; ++j) {
1371  goodShares[j] = shares[i][goodservers[j]];
1372  }
1373  FX L_i;
1374  interpolate(L_i, goodIndices, goodShares);
1375  L.push_back(L_i);
1376  }
1377 
1378 #ifdef VERBOSE_CH_MULTI
1379  for (unsigned int i = 0; i < m; ++i) {
1380  std::cerr << "L[" << i << "](z) = " << L[i] << " (" << deg(L[i]) << ")\n";
1381  }
1382 #endif
1383 
1384  vector<FX> powers_of_N;
1385  powers_of_N.push_back(FX(0, 1));
1386  for (unsigned int i = 1; i <= k; ++i) {
1387  powers_of_N.push_back(powers_of_N[i-1] * N);
1388  }
1389 
1390 #ifdef VERBOSE_CH_MULTI
1391  for (unsigned int i = 0; i <= k; ++i) {
1392  std::cerr << "powers_of_N[" << i << "](z) = " << powers_of_N[i] << ")\n";
1393  }
1394 #endif
1395 
1396  // Create lattice basis
1397  vector<vector<FX> > lattice(m+1, vector<FX>(m+1));
1398  lattice[0][0] = N;
1399  FX z_toell(ell, 1);
1400  for (unsigned int i = 0; i < m; ++i) {
1401  lattice[i+1][0] = -(L[i]);
1402  lattice[i+1][i+1] = z_toell;
1403  }
1404 
1405 #ifdef VERBOSE_CH_MULTI
1406  std::cerr << "lattice =\n";
1407  for (unsigned int i = 0; i <= m; ++i) {
1408  for (unsigned int j = 0; j <= m; ++j) {
1409  std::cerr << "\t" << i << "," << j << ":\t" << lattice[i][j] << "\n";
1410  }
1411  }
1412 #endif
1413 
1414  vector<vector<FX> > aux (m+1, vector<FX>());
1415 
1416 #ifdef TIME_PARTS
1417  struct timeval st, et;
1418  gettimeofday(&st, NULL);
1419 #endif
1420 
1421  vector<vector<FX> > reducedLattice = reduce_lattice_MS(lattice, aux);
1422 
1423 #ifdef TIME_PARTS
1424  gettimeofday(&et, NULL);
1425  unsigned long long elapsedus = ((unsigned long long)(et.tv_sec -
1426  st.tv_sec)) * 1000000 + (et.tv_usec - st.tv_usec);
1427  tsout << "lattice reduction," << elapsedus << ",";
1428 #endif
1429 
1430 #ifdef VERBOSE_CH_MULTI
1431  std::cerr << "reducedLattice =\n";
1432  for (unsigned int i = 0; i < m+1; ++i) {
1433  for (unsigned int j = 0; j < m+1; ++j) {
1434  std::cerr << "\t" << i << "," << j << ":\t" << reducedLattice[i][j] << "\n";
1435  }
1436  }
1437  std::cerr << "reducedLattice degrees:\n";
1438  for (unsigned int i = 0; i < m+1; ++i) {
1439  std::cerr << "\t";
1440  for (unsigned int j = 0; j < m+1; ++j) {
1441  std::cerr << deg(reducedLattice[i][j]) << "\t";
1442  }
1443  std::cerr << "\n";
1444  }
1445 #endif
1446 
1447  vector<unsigned int> smallRows;
1448  for (unsigned int i = 0; i < m+1; ++i) {
1449  int maxdeg = -2;
1450  for (unsigned int j = 0; j < m+1; ++j) {
1451  if (deg(reducedLattice[i][j]) > maxdeg) {
1452  maxdeg = deg(reducedLattice[i][j]);
1453  }
1454  }
1455 // std::cerr << "i = " << i << ", maxdeg = " << maxdeg << ", h = " << h << "\n";
1456  if (maxdeg < (int)(h)) {
1457  smallRows.push_back(i);
1458  }
1459  }
1460 
1461 #ifdef VERBOSE_CH_MULTI
1462  std::cerr << "smallRows =";
1463  vector<unsigned int>::iterator sriter;
1464  for (sriter = smallRows.begin(); sriter != smallRows.end(); ++sriter) {
1465  std::cerr << " " << *sriter;
1466  }
1467  std::cerr << "\n";
1468 #endif
1469 
1470  if (smallRows.size() < m) {
1471 
1472  // If t=k=1, then fail
1473  if (t == 1 && k == 1) {
1474 #ifdef VERBOSE_CH_MULTI
1475  std::cerr << "FAIL: explicit t=k=1 failed\n";
1476 #endif
1477  return vector<RecoveryPolyMulti<FX> >(); // Fail
1478  }
1479 
1480 #ifdef VERBOSE_CH_MULTI
1481  std::cerr << "Not enough small vectors with t=k=1. Trying larger values...\n";
1482 #endif
1483 
1484  vector<vector<vector<FX> > > coeff_by_expts; // coeff_by_expts[i][j][p] = [x^p](x_i - L_i(z))^j
1485  for (unsigned int i = 0; i < m; ++i) {
1486  vector<vector<FX> > coeffs_for_var;
1487  coeffs_for_var.push_back(vector<FX>(1, FX(0, 1)));
1488  for (unsigned int j = 1; j <= t; ++j) {
1489  vector<FX> current_j;
1490  for (unsigned int p = 0; p <= j; ++p) {
1491  FX current;
1492  if (p == 0) {
1493  current = coeffs_for_var[j-1][p] * (-(L[i]));
1494  } else if (p == j) {
1495  current = 1;
1496  } else {
1497  current = coeffs_for_var[j-1][p] * (-(L[i]));
1498  current += coeffs_for_var[j-1][p-1];
1499  }
1500  current_j.push_back(current);
1501  }
1502  coeffs_for_var.push_back(current_j);
1503  }
1504  coeff_by_expts.push_back(coeffs_for_var);
1505  }
1506 
1507 #ifdef VERBOSE_CH_MULTI
1508  std::cerr << "coeff_by_expts =\n";
1509  for (unsigned int i = 0; i < m; ++i) {
1510  for (unsigned int j = 0; j <= t; ++j) {
1511  for (unsigned int p = 0; p <= j; ++p) {
1512  std::cerr << "\t" << i << "," << j << "," << p << "\t" << coeff_by_expts[i][j][p] << "\n";
1513  }
1514  }
1515  }
1516 #endif
1517 
1518  vector<vector<unsigned int> > order_of_expts;
1519  order_of_expts.push_back(vector<unsigned int>(m, 0));
1520  vector<vector<vector<unsigned int> > > prev_t;
1521  for (unsigned int i = 0; i < m; ++i) {
1522  vector<unsigned int> current (m, 0);
1523  current[i] = 1;
1524  prev_t.push_back(vector<vector<unsigned int> >(1, current));
1525  order_of_expts.push_back(current);
1526  }
1527  for (unsigned i = 2; i <= t; ++i) {
1528  vector<vector<vector<unsigned int> > > curr_t;
1529  for (unsigned int j = 0; j < m; ++j) {
1530  vector<vector<unsigned int> > current_j;
1531  for (unsigned int p = j; p < m; ++p) {
1532  vector<vector<unsigned int> >::iterator iter;
1533  for (iter = prev_t[p].begin(); iter != prev_t[p].end(); ++iter) {
1534  vector<unsigned int> current = *iter;
1535  current[j] += 1;
1536  current_j.push_back(current);
1537  order_of_expts.push_back(current);
1538  }
1539  }
1540  curr_t.push_back(current_j);
1541  }
1542  prev_t = curr_t;
1543  }
1544 
1545  vector<unsigned int> exptSum;
1546  for (unsigned int i = 0; i < dim; ++i) {
1547  unsigned int current = 0;
1548  vector<unsigned int> expts = order_of_expts[i];
1549  for (unsigned int p = 0; p < m; ++p) {
1550  current += expts[p];
1551  }
1552  exptSum.push_back(current);
1553  }
1554 
1555 #ifdef VERBOSE_CH_MULTI
1556  std::cerr << "order_of_expts, exptSum =\n";
1557  for (unsigned int i = 0; i < dim; ++i) {
1558  std::cerr << "\t";
1559  for (unsigned int j = 0; j < m; ++j) {
1560  std::cerr << order_of_expts[i][j] << " ";
1561  }
1562  std::cerr << ", " << exptSum[i] << "\n";
1563  }
1564 #endif
1565 
1566  vector<vector<FX> > lattice2;
1567  for (unsigned int i = 0; i < dim; ++i) {
1568  vector<unsigned int> rowExpts = order_of_expts[i];
1569  vector<FX> row;
1570  for (unsigned j = 0; j < dim; ++j) {
1571  vector<unsigned int> termExpts = order_of_expts[j];
1572  bool nonZero = true;
1573  for (unsigned int p = 0; p < m; ++p) {
1574  if (termExpts[p] > rowExpts[p]) {
1575  nonZero = false;
1576  break;
1577  }
1578  }
1579  if (!nonZero) {
1580  row.push_back(FX());
1581  continue;
1582  }
1583  FX termCoeff = FX(0, 1);
1584  for (unsigned int p = 0; p < m; ++p) {
1585  termCoeff *= coeff_by_expts[p][rowExpts[p]][termExpts[p]];
1586  }
1587  termCoeff *= power(z_toell, exptSum[j]);
1588  if (exptSum[i] < k) {
1589  termCoeff *= powers_of_N[k - exptSum[i]];
1590  }
1591  row.push_back(termCoeff);
1592  }
1593  lattice2.push_back(row);
1594  }
1595 
1596 #ifdef VERBOSE_CH_MULTI
1597  std::cerr << "lattice2 =\n";
1598  for (unsigned int i = 0; i < dim; ++i) {
1599  for (unsigned int j = 0; j < dim; ++j) {
1600  std::cerr << "\t" << i << "," << j << "\t" << lattice2[i][j] << "\n";
1601  }
1602  }
1603  std::cerr << "lattice2 non-zero elements:\n";
1604  for (unsigned int i = 0; i < dim; ++i) {
1605  std::cerr << "\t";
1606  for (unsigned int j = 0; j < dim; ++j) {
1607  std::cerr << (IsZero(lattice2[i][j]) ? " " : "X");
1608  }
1609  std::cerr << "\n";
1610  }
1611 #endif
1612 
1613  // Reduce lattice basis using Mulders-Storjohann
1614  vector<vector<FX> > aux (dim, vector<FX>());
1615  //vector<vector<FX> > reducedLattice2WSpoon = reduce_lattice_MS(lattice2, aux, h*k, m);
1616  vector<vector<FX> > reducedLattice2WSpoon = reduce_lattice_MS(lattice2, aux);
1617 
1618 #ifdef VERBOSE_CH_MULTI
1619  std::cerr << "reducedLattice2WSpoon =\n";
1620  for (unsigned int i = 0; i < dim; ++i) {
1621  for (unsigned int j = 0; j < dim; ++j) {
1622  std::cerr << "\t" << i << "," << j << ":\t" << reducedLattice2WSpoon[i][j] << "\n";
1623  }
1624  }
1625 
1626  std::cerr << "reducedLattice2WSpoon degrees:\n";
1627  for (unsigned int i = 0; i < dim; ++i) {
1628  std::cerr << "\t";
1629  for (unsigned int j = 0; j < dim; ++j) {
1630  std::cerr << deg(reducedLattice2WSpoon[i][j]) << "\t";
1631  }
1632  std::cerr << "\n";
1633  }
1634 #endif
1635 
1636  // Take out the wooden spoon
1637  vector<vector<FX> > reducedLattice2;
1638  for (unsigned int i = 0; i < dim; ++i) {
1639  vector<FX> row;
1640  for (unsigned int j = 0; j < dim; ++j) {
1641 // std::cerr << "Removing spoon from " << i << "," << j << "\n";
1642 // std::cerr << "\torder_of_expts[" << j << "], exptSum[" << j << "] =";
1643 // for (unsigned int p = 0; p < m; ++p) {
1644 // std::cerr << " " << order_of_expts[j][p];
1645 // }
1646 // std::cerr << ", " << exptSum[j] << "\n";
1647 // std::cerr << "\treducedLattice2WSpoon[" << i << "][" << j << "] = " << reducedLattice2WSpoon[i][j] << "\n";
1648 // std::cerr << "\tz_toell^exptSum[" << j << "] = " << power(z_toell, exptSum[j]) << "\n";
1649 // std::cerr << "\treducedLattice2WSpoon[" << i << "][" << j << "] / power(z_toell, exptSum[" << j << "]) = " << reducedLattice2WSpoon[i][j] / power(z_toell, exptSum[j]) << "\n";
1650  row.push_back(reducedLattice2WSpoon[i][j] / power(z_toell, exptSum[j]));
1651  }
1652  reducedLattice2.push_back(row);
1653  }
1654 
1655 #ifdef VERBOSE_CH_MULTI
1656  std::cerr << "reducedLattice2 =\n";
1657  for (unsigned int i = 0; i < dim; ++i) {
1658  for (unsigned int j = 0; j < dim; ++j) {
1659  std::cerr << "\t" << i << "," << j << ":\t" << reducedLattice2[i][j] << "\n";
1660  }
1661  }
1662 
1663  std::cerr << "reducedLattice2 degrees:\n";
1664  for (unsigned int i = 0; i < dim; ++i) {
1665  std::cerr << "\t";
1666  for (unsigned int j = 0; j < dim; ++j) {
1667  std::cerr << deg(reducedLattice2[i][j]) << "\t";
1668  }
1669  std::cerr << "\n";
1670  }
1671 #endif
1672 
1673  map<int, unsigned int> reducedDegrees;
1674  vector<unsigned int> smallRows;
1675  for (unsigned int i = 0; i < dim; ++i) {
1676  int maxdeg = -2;
1677  for (unsigned int j = 0; j < dim; ++j) {
1678  if (deg(reducedLattice2[i][j]) > maxdeg) {
1679  maxdeg = deg(reducedLattice2[i][j]);
1680  }
1681  }
1682  if (maxdeg < (int)(k*h)) {
1683  smallRows.push_back(i);
1684  }
1685  map<int, unsigned int>::iterator it = reducedDegrees.find(maxdeg);
1686  if (it != reducedDegrees.end()) {
1687  reducedDegrees[maxdeg] += 1;
1688  } else {
1689  reducedDegrees[maxdeg] = 1;
1690  }
1691  }
1692 
1693 // std::cerr << "reducedDegrees =\n";
1694 // for (map<int, unsigned int>::iterator it = reducedDegrees.begin();
1695 // it != reducedDegrees.end(); ++it) {
1696 // std::cerr << "\t" << it->first << "\t" << it->second << "\n";
1697 // }
1698 
1699  std::cerr << "reducedLattice2 max degrees:";
1700  for (map<int, unsigned int>::iterator it = reducedDegrees.begin();
1701  it != reducedDegrees.end(); ++it) {
1702  for (unsigned int j = 0; j < it->second; ++j) {
1703  std::cerr << " " << it->first;
1704  }
1705  }
1706  std::cerr << "\n";
1707 
1708 #ifdef VERBOSE_CH_MULTI
1709  std::cerr << "smallRows =";
1710  vector<unsigned int>::iterator sriter;
1711  for (sriter = smallRows.begin(); sriter != smallRows.end(); ++sriter) {
1712  std::cerr << " " << *sriter;
1713  }
1714  std::cerr << " (" << smallRows.size() << ")\n";
1715 #endif
1716 
1717  if (smallRows.size() < m) {
1718  std::cerr << "FAIL: few_small_vectors: Not enough small vectors\n";
1719  return vector<RecoveryPolyMulti<FX> >(); // Fail
1720  }
1721 
1722  std::stringstream tosage;
1723  for (vector<unsigned int>::iterator iter = smallRows.begin();
1724  iter != smallRows.end();
1725  ++iter) {
1726  tosage << "{" << reducedLattice2[*iter][0];
1727  for (unsigned int j = 1; j < dim; ++j) {
1728  tosage << "," << reducedLattice2[*iter][j];
1729  }
1730  tosage << "}\n";
1731  }
1732 
1733  const std::string tosageFile = "/tmp/tosage.txt";
1734  const std::string fromsageFile = "/tmp/fromsage.txt";
1735  std::ofstream tosageStream(tosageFile.c_str());
1736  tosageStream << tosage.str();
1737  tosageStream.close();
1738 
1739  std::stringstream cmd;
1740  cmd << "sage solveGroebnerBasis.sage " << m << " " << t;
1741 // This needs to be changed. Possibly use typeid from typeinfo
1742 #ifdef USE_GF28
1743  cmd << " gf28";
1744 #elif defined USE_GF24
1745  cmd << " gf24";
1746 #elif defined USE_W8
1747  cmd << " w8";
1748 #elif defined USE_W32
1749  cmd << " w32";
1750 #else
1751  cmd << " w128";
1752 #endif
1753  cmd << " < " << tosageFile << " > " << fromsageFile;
1754 
1755  if (system(cmd.str().c_str()) != 0) {
1756 #ifdef VERBOSE_CH_MULTI
1757  std::cerr << "FAIL: sage failed\n";
1758 #endif
1759  return vector<RecoveryPolyMulti<FX> >(); // Fail
1760  }
1761 
1762  vector<vector<FX> > fromsage;
1763  unsigned int rows;
1764  std::ifstream fromsageStream(fromsageFile.c_str());
1765  fromsageStream >> rows;
1766  for (unsigned int i = 0; i < rows; ++i) {
1767  vector<FX> row;
1768  for (unsigned int j = 0; j < dim; ++j) {
1769  FX current;
1770  fromsageStream >> current;
1771  row.push_back(current);
1772  }
1773  fromsage.push_back(row);
1774  }
1775  fromsageStream.close();
1776 
1777 #ifdef VERBOSE_CH_MULTI
1778  std::cerr << "rows = " << rows << "\n";
1779  std::cerr << "fromsage =\n";
1780  for (unsigned int i = 0; i < rows; ++i) {
1781  for (unsigned int j = 0; j < dim; ++j) {
1782  std::cerr << "\t" << i << "," << j << "\t" << fromsage[i][j] << "\n";
1783  }
1784  }
1785 #endif
1786 
1787  // Vars in each row
1788  vector<map<unsigned int, bool> > hasVars(rows);
1789  for (unsigned int i = 0; i < dim; ++i) {
1790  vector<unsigned int> expts = order_of_expts[i];
1791  for (unsigned int j = 0; j < rows; ++j) {
1792  if (fromsage[j][i] != 0) {
1793  for (unsigned int p = 0; p < m; ++p) {
1794  if (expts[p] != 0) {
1795  hasVars[j][p] = true;
1796  }
1797  }
1798  }
1799  }
1800  }
1801 
1802 #ifdef VERBOSE_CH_MULTI
1803  std::cerr << "hasVars =\n";
1804  for (unsigned int i = 0; i < rows; ++i) {
1805  std::cerr << "\tRow " << i << "\t";
1806  typename map<unsigned int, bool>::iterator varIter;
1807  for (varIter = hasVars[i].begin(); varIter != hasVars[i].end(); ++varIter) {
1808  std::cerr << varIter->first << " ";
1809  }
1810  std::cerr << "\n";
1811  }
1812 #endif
1813 
1814  // Sort by # of vars
1815  vector<unsigned int> row_order;
1816  for (unsigned int i = 0; i <= m; ++i) {
1817  for (unsigned int j = 0; j < rows; ++j) {
1818  if (hasVars[j].size() == i) {
1819  row_order.push_back(j);
1820  }
1821  }
1822  }
1823 
1824 #ifdef VERBOSE_CH_MULTI
1825  std::cerr << "row_order =";
1826  for (unsigned int i = 0; i < rows; ++i) {
1827  std::cerr << " " << row_order[i];
1828  }
1829  std::cerr << "\n";
1830 #endif
1831 
1832  // Work to find solutions
1833  vector<map<unsigned int, FX> > solutions =
1834  solve_partial_solution(ell, h, map<unsigned int, FX>(), fromsage, row_order, order_of_expts);
1835 
1836  if (solutions.size() == 0) {
1837 #ifdef VERBOSE_CH_MULTI
1838  std::cerr << "FAIL: no solutions found\n";
1839 #endif
1840  return vector<RecoveryPolyMulti<FX> >(); // Fail
1841  }
1842 
1843 #ifdef VERBOSE_CH_MULTI
1844  std::cerr << "solutions =\n";
1845  for (unsigned int i = 0; i < solutions.size(); ++i) {
1846  for (unsigned int j = 0; j < m; ++j) {
1847  std::cerr << "\tx" << j << "\t";
1848  typename map<unsigned int, FX>::iterator it = solutions[i].find(j);
1849  if (it != solutions[i].end()) {
1850  std::cerr << solutions[i][j] << " [ ";
1851  for (unsigned int p = 0; p < n; ++p) {
1852  F phival;
1853  eval(phival, solutions[i][j], indices[goodservers[p]]);
1854  if (phival == shares[j][goodservers[p]]) {
1855  std::cerr << p << " ";
1856  }
1857  }
1858  std::cerr << "]";
1859 
1860  }
1861  std::cerr << "\n";
1862  }
1863  std::cerr << "\n";
1864  }
1865 #endif
1866 
1867  vector<RecoveryPolyMulti<FX> > polys;
1868  for (unsigned int j = 0; j < solutions.size(); ++j) {
1869  // For each polynomial in the solution, check how many input points it agrees
1870  // with. If it's at least h, add it to the list of polys to return.
1871  map<unsigned int, FX> solution = solutions[j];
1872 
1873  // For now
1874  if (solution.size() != m) {
1875  continue;
1876  }
1877 
1878  vector<unsigned short>::iterator gooditer;
1879  vector<unsigned short> vecagree = goodservers;
1880  vector<FX> vecsolution;
1881  for (unsigned int i = 0; i < m; ++i) {
1882  for (gooditer = vecagree.begin(); gooditer != vecagree.end(); ) {
1883  F phival;
1884  eval(phival, solution[i], indices[*gooditer]);
1885  if (phival == shares[i][*gooditer]) {
1886  ++gooditer;
1887  } else {
1888  gooditer = vecagree.erase(gooditer);
1889  }
1890  }
1891  vecsolution.push_back(solution[i]);
1892  }
1893  if (vecagree.size() >= h) {
1894  RecoveryPolyMulti<FX> n(vecagree, vecsolution);
1895  polys.push_back(n);
1896  }
1897  }
1898 
1899 #ifdef VERBOSE_CH_MULTI
1900  std::cerr << "polys = \n";
1901  for (unsigned int i = 0; i < polys.size(); ++i) {
1902  for (unsigned int j = 0; j < m; ++j) {
1903  std::cerr << "\t" << j << "\t" << polys[i].phis[j] << "\n";
1904  }
1905  std::cerr << "\n";
1906  }
1907 #endif
1908 
1909  return polys;
1910 
1911  } else {
1912  // Continue with t=k=1 work
1913  vector<vector<FX> > A;
1914  vector<FX> b;
1915  vector<unsigned int>::iterator smallIter = smallRows.begin();
1916  for (unsigned int i = 0; smallIter != smallRows.end() && i < m; ++smallIter, ++i) {
1917  vector<FX> currRow;
1918  for (unsigned int j = 1; j <= m; ++j) {
1919  currRow.push_back(RightShift(reducedLattice[*smallIter][j], ell));
1920  }
1921  A.push_back(currRow);
1922  b.push_back(-(reducedLattice[*smallIter][0]));
1923  }
1924 
1925 #ifdef VERBOSE_CH_MULTI
1926  std::cerr << "A =\n";
1927  for (unsigned int i = 0; i < m; ++i) {
1928  for (unsigned int j = 0; j < m; ++j) {
1929  std::cerr << "\t" << i << "," << j << ":\t" << A[i][j] << "\n";
1930  }
1931  }
1932  std::cerr << "b =\n";
1933  for (unsigned int i = 0; i < m; ++i) {
1934  std::cerr << "\t" << i << ":\t" << b[i] << "\n";
1935  }
1936 #endif
1937 
1938 #ifdef TIME_PARTS
1939  gettimeofday(&st, NULL);
1940 #endif
1941 
1942  //vector<FX> solution = solve_linsys_FX(A, b, t+1);
1943  vector<FX> solution = solve_linsys_FX(A, b);
1944 
1945 #ifdef TIME_PARTS
1946  gettimeofday(&et, NULL);
1947  unsigned long long elapsedus = ((unsigned long long)(et.tv_sec -
1948  st.tv_sec)) * 1000000 + (et.tv_usec - st.tv_usec);
1949  tsout << "solving linear system," << elapsedus << ",";
1950 #endif
1951 
1952  if (solution.size() == 0) {
1953  return vector<RecoveryPolyMulti<FX> >(); // Fail
1954  }
1955 
1956 #ifdef VERBOSE_CH_MULTI
1957  std::cerr << "solution =\n";
1958  for (unsigned int i = 0; i < m; ++i) {
1959  std::cerr << "\t" << i << ":\t" << solution[i] << "\n";
1960  }
1961 #endif
1962 
1963  // For each polynomial in the solution, check how many input points it agrees
1964  // with. If it's at least h, add it to the list of polys to return.
1965  vector< RecoveryPolyMulti<FX> > polys;
1966  vector<unsigned short>::iterator gooditer;
1967  vector<unsigned short> vecagree = goodservers;
1968  for (unsigned int i = 0; i < m; ++i) {
1969  for (gooditer = vecagree.begin(); gooditer != vecagree.end(); ) {
1970  F phival;
1971  eval(phival, solution[i], indices[*gooditer]);
1972  if (phival == shares[i][*gooditer]) {
1973  ++gooditer;
1974  } else {
1975  gooditer = vecagree.erase(gooditer);
1976  }
1977  }
1978  }
1979  if (vecagree.size() >= h) {
1980  RecoveryPolyMulti<FX> n(vecagree, solution);
1981  polys.push_back(n);
1982  }
1983 
1984  // Change t,k to 1
1985  t = 1;
1986  k = 1;
1987 
1988 #ifdef VERBOSE_CH_MULTI
1989  std::cerr << "polys = \n";
1990  for (unsigned int i = 0; i < polys.size(); ++i) {
1991  for (unsigned int j = 0; j < m; ++j) {
1992  std::cerr << "\t" << j << "\t" << polys[i].phis[j] << "\n";
1993  }
1994  std::cerr << "\n";
1995  }
1996 #endif
1997 
1998 #ifdef TIME_PARTS
1999  tsout << "\n";
2000 
2001  char * testOutfile = getenv("TIME_PARTS_OUTFILE");
2002  if (testOutfile) {
2003  std::ofstream timefile;
2004  timefile.open (testOutfile, ios::app);
2005  timefile << tsout.str();
2006  timefile.close();
2007  } else {
2008  std::cerr << "Time Parts: " << tsout.str();
2009  }
2010 #endif
2011 
2012  return polys;
2013  }
2014 }
2015 #endif
2016 
2017 template<class F, class vec_F, class FX, class FXY, class mat_F>
2018 vector<RecoveryPolyMulti<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_ch_tk1(
2019  unsigned int ell, unsigned int h, unsigned int m,
2020  const vector<unsigned short> &goodservers,
2021  const vec_F &indices, const vector<vec_F> &shares) {
2022 
2023 #ifdef VERBOSE_CH_TK1
2024  std::cerr << "Starting Cohn-Heninger Linear Multi-Polynomial algorithm...\n";
2025 #endif
2026 
2027  // Get number of responses
2028  unsigned int n = goodservers.size();
2029 
2030 #ifdef VERBOSE_CH_TK1
2031  std::cerr << "n = " << n << "\n";
2032  std::cerr << "ell = " << ell << "\n";
2033  std::cerr << "h = " << h << "\n";
2034  std::cerr << "m = " << m << "\n";
2035 #endif
2036 
2037 #ifdef TIME_PARTS
2038  std::stringstream tsout;
2039  tsout << n << "," << ell << "," << h << ",";
2040 #endif
2041 
2042  // Create N(z)
2043  FX N;
2044  SetCoeff(N, 0, 1);
2045  for (unsigned int i = 0; i < n; ++i) {
2046  FX newTerm;
2047  SetCoeff(newTerm, 0, -(indices[goodservers[i]]));
2048  SetCoeff(newTerm, 1);
2049  N *= newTerm;
2050  }
2051 
2052 #ifdef VERBOSE_CH_TK1
2053  std::cerr << "N(z) = " << N << " (" << deg(N) << ")\n";
2054 #endif
2055 
2056  // Create L[i](z), the interpolation of points in shares[i]
2057  vector<FX> L;
2058  vec_F goodIndices(INIT_SIZE, n);
2059  for (unsigned int j = 0; j < n; ++j) {
2060  goodIndices[j] = indices[goodservers[j]];
2061  }
2062  for (unsigned int i = 0; i < m; ++i) {
2063  vec_F goodShares(INIT_SIZE, n);
2064  for (unsigned int j = 0; j < n; ++j) {
2065  goodShares[j] = shares[i][goodservers[j]];
2066  }
2067  FX L_i;
2068  interpolate(L_i, goodIndices, goodShares);
2069  L.push_back(L_i);
2070  }
2071 
2072 #ifdef VERBOSE_CH_TK1
2073  for (unsigned int i = 0; i < m; ++i) {
2074  std::cerr << "L[" << i << "](z) = " << L[i] << " (" << deg(L[i]) << ")\n";
2075  }
2076 #endif
2077 
2078  // Create lattice basis
2079  vector<vector<FX> > lattice(m+1, vector<FX>(m+1));
2080  lattice[0][0] = N;
2081  FX z_toell(ell, 1);
2082  for (unsigned int i = 0; i < m; ++i) {
2083  lattice[i+1][0] = -(L[i]);
2084  lattice[i+1][i+1] = z_toell;
2085  }
2086 
2087 #ifdef VERBOSE_CH_TK1
2088  std::cerr << "lattice =\n";
2089  for (unsigned int i = 0; i <= m; ++i) {
2090  for (unsigned int j = 0; j <= m; ++j) {
2091  std::cerr << "\t" << i << "," << j << ":\t" << lattice[i][j] << "\n";
2092  }
2093  }
2094 #endif
2095 
2096  vector<vector<FX> > aux (m+1, vector<FX>());
2097 
2098 #ifdef TIME_PARTS
2099  struct timeval st, et;
2100  gettimeofday(&st, NULL);
2101 #endif
2102 
2103  vector<vector<FX> > reducedLattice = reduce_lattice_MS(lattice, aux);
2104 
2105 #ifdef TIME_PARTS
2106  gettimeofday(&et, NULL);
2107  unsigned long long elapsedus = ((unsigned long long)(et.tv_sec -
2108  st.tv_sec)) * 1000000 + (et.tv_usec - st.tv_usec);
2109  tsout << "lattice reduction," << elapsedus << ",";
2110 #endif
2111 
2112 #ifdef VERBOSE_CH_TK1
2113  std::cerr << "reducedLattice =\n";
2114  for (unsigned int i = 0; i < m+1; ++i) {
2115  for (unsigned int j = 0; j < m+1; ++j) {
2116  std::cerr << "\t" << i << "," << j << ":\t" << reducedLattice[i][j] << "\n";
2117  }
2118  }
2119  std::cerr << "reducedLattice degrees:\n";
2120  for (unsigned int i = 0; i < m+1; ++i) {
2121  std::cerr << "\t";
2122  for (unsigned int j = 0; j < m+1; ++j) {
2123  std::cerr << deg(reducedLattice[i][j]) << "\t";
2124  }
2125  std::cerr << "\n";
2126  }
2127 #endif
2128 
2129  vector<unsigned int> smallRows;
2130  for (unsigned int i = 0; i < m+1; ++i) {
2131  int maxdeg = -2;
2132  for (unsigned int j = 0; j < m+1; ++j) {
2133  if (deg(reducedLattice[i][j]) > maxdeg) {
2134  maxdeg = deg(reducedLattice[i][j]);
2135  }
2136  }
2137 // std::cerr << "i = " << i << ", maxdeg = " << maxdeg << ", h = " << h << "\n";
2138  if (maxdeg < (int)(h)) {
2139  smallRows.push_back(i);
2140  }
2141  }
2142 
2143 #ifdef VERBOSE_CH_TK1
2144  std::cerr << "smallRows =";
2145  vector<unsigned int>::iterator sriter;
2146  for (sriter = smallRows.begin(); sriter != smallRows.end(); ++sriter) {
2147  std::cerr << " " << *sriter;
2148  }
2149  std::cerr << "\n";
2150 #endif
2151 
2152  if (smallRows.size() < m) {
2153 #ifdef VERBOSE_CH_TK1
2154  std::cerr << "FAIL: Not enough small rows\n";
2155 #endif
2156  return vector<RecoveryPolyMulti<FX> >(); // FAIL
2157  }
2158 
2159  vector<vector<FX> > A;
2160  vector<FX> b;
2161  vector<unsigned int>::iterator smallIter = smallRows.begin();
2162  for (unsigned int i = 0; smallIter != smallRows.end() && i < m; ++smallIter, ++i) {
2163  vector<FX> currRow;
2164  for (unsigned int j = 1; j <= m; ++j) {
2165  currRow.push_back(RightShift(reducedLattice[*smallIter][j], ell));
2166  }
2167  A.push_back(currRow);
2168  b.push_back(-(reducedLattice[*smallIter][0]));
2169  }
2170 
2171 #ifdef VERBOSE_CH_TK1
2172  std::cerr << "A =\n";
2173  for (unsigned int i = 0; i < m; ++i) {
2174  for (unsigned int j = 0; j < m; ++j) {
2175  std::cerr << "\t" << i << "," << j << ":\t" << A[i][j] << "\n";
2176  }
2177  }
2178  std::cerr << "b =\n";
2179  for (unsigned int i = 0; i < m; ++i) {
2180  std::cerr << "\t" << i << ":\t" << b[i] << "\n";
2181  }
2182 #endif
2183 
2184 #ifdef TIME_PARTS
2185  gettimeofday(&st, NULL);
2186 #endif
2187 
2188  //vector<FX> solution = solve_linsys_FX(A, b, t+1);
2189  vector<FX> solution = solve_linsys_FX(A, b);
2190 
2191 #ifdef TIME_PARTS
2192  gettimeofday(&et, NULL);
2193  unsigned long long elapsedus = ((unsigned long long)(et.tv_sec -
2194  st.tv_sec)) * 1000000 + (et.tv_usec - st.tv_usec);
2195  tsout << "solving linear system," << elapsedus << ",";
2196 #endif
2197 
2198  if (solution.size() == 0) {
2199 #ifdef VERBOSE_CH_TK1
2200  std::cerr << "FAIL: solve_linsys_FX failed\n";
2201 #endif
2202  return vector<RecoveryPolyMulti<FX> >(); // Fail
2203  }
2204 
2205 #ifdef VERBOSE_CH_TK1
2206  std::cerr << "solution =\n";
2207  for (unsigned int i = 0; i < m; ++i) {
2208  std::cerr << "\t" << i << ":\t" << solution[i] << "\n";
2209  }
2210 #endif
2211 
2212  // For each polynomial in the solution, check how many input points it agrees
2213  // with. If it's at least h, add it to the list of polys to return.
2214  vector< RecoveryPolyMulti<FX> > polys;
2215  vector<unsigned short>::iterator gooditer;
2216  vector<unsigned short> vecagree = goodservers;
2217  for (unsigned int i = 0; i < m; ++i) {
2218  for (gooditer = vecagree.begin(); gooditer != vecagree.end(); ) {
2219  F phival;
2220  eval(phival, solution[i], indices[*gooditer]);
2221  if (phival == shares[i][*gooditer]) {
2222  ++gooditer;
2223  } else {
2224  gooditer = vecagree.erase(gooditer);
2225  }
2226  }
2227  }
2228  if (vecagree.size() >= h) {
2229  RecoveryPolyMulti<FX> n(vecagree, solution);
2230  polys.push_back(n);
2231  }
2232 
2233 #ifdef VERBOSE_CH_TK1
2234  std::cerr << "polys = \n";
2235  for (unsigned int i = 0; i < polys.size(); ++i) {
2236  for (unsigned int j = 0; j < m; ++j) {
2237  std::cerr << "\t" << j << "\t" << polys[i].phis[j] << "\n";
2238  }
2239  std::cerr << "\n";
2240  }
2241 #endif
2242 
2243 #ifdef TIME_PARTS
2244  tsout << "\n";
2245 
2246  char * testOutfile = getenv("TIME_PARTS_OUTFILE");
2247  if (testOutfile) {
2248  std::ofstream timefile;
2249  timefile.open (testOutfile, ios::app);
2250  timefile << tsout.str();
2251  timefile.close();
2252  } else {
2253  std::cerr << "Time Parts: " << tsout.str();
2254  }
2255 #endif
2256 
2257  return polys;
2258 }
2259 
2260 /*
2261 // Comparison functions used to let polynomials be keys for maps
2262 bool cmp (const GF2EX& a, const GF2EX& b) {
2263  if (deg(a) != deg(b)) {
2264  return deg(a) < deg(b);
2265  }
2266  for (int i = deg(a); i >= 0; --i) {
2267  unsigned char byte_a, byte_b;
2268  BytesFromGF2X(&byte_a, rep(coeff(a, i)), 1);
2269  BytesFromGF2X(&byte_b, rep(coeff(b, i)), 1);
2270  if (byte_a != byte_b) {
2271  return byte_a < byte_b;
2272  }
2273  }
2274  return false;
2275 }
2276 
2277 bool cmp (const ZZ_pX& a, const ZZ_pX& b) {
2278  if (deg(a) != deg(b)) {
2279  return deg(a) < deg(b);
2280  }
2281  for (int i = deg(a); i >= 0; --i) {
2282  ZZ rep_a = rep(coeff(a, i));
2283  ZZ rep_b = rep(coeff(b, i));
2284  if (rep_a != rep_b) {
2285  return rep_a < rep_b;
2286  }
2287  }
2288  return false;
2289 }
2290 */
2291 
2292 template<class F, class vec_F, class FX, class FXY, class mat_F>
2293 class cmpPolys {
2294 public:
2295  bool operator() (const FX& a, const FX& b) const {
2296  if (a == b) {
2297  return false;
2298  }
2299  return cmp(a, b);
2300  }
2301 };
2302 
2303 template<class F, class vec_F, class FX, class FXY, class mat_F>
2304 vector<RecoveryPoly<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_dp (
2305  unsigned int ell, unsigned int h,
2306  const vector<unsigned short> &goodservers,
2307  const vec_F &indices, const vec_F &shares,
2308  const DPType dptype, unsigned int gord)
2309 {
2310  unsigned int n = goodservers.size();
2311 
2312  map<FX, std::set<unsigned short>, cmpPolys<F,vec_F,FX,FXY,mat_F> > soln_map;
2313  vector<unsigned short> assume_servers, sub_goodservers;
2314 
2315 #ifdef VERBOSE_DP
2316  std::cerr << "\tindices = ";
2317  for (unsigned int i = 0; i < n; ++i) {
2318  std::cerr << indices[goodservers[i]] << " ";
2319  }
2320  std::cerr << "\n";
2321  std::cerr << "\tshares = ";
2322  for (unsigned int i = 0; i < n; ++i) {
2323  std::cerr << shares[goodservers[i]] << " ";
2324  }
2325  std::cerr << "\n";
2326 #endif
2327  if (dptype == ASSUME_CORRECT) {
2328 #ifdef VERBOSE_DP
2329  std::cerr << "ASSUME CORRECT: g = " << gord << "\n";
2330 #endif
2331  assume_servers.insert(assume_servers.begin(), goodservers.begin(), goodservers.begin() + n - h + gord);
2332  subset_iterator subIter = subset_iterator(assume_servers, gord);
2333  while( ! subIter.atend() ) {
2334 #ifdef VERBOSE_DP
2335  std::cerr << "\t*subIter = ";
2336  for (unsigned int i = 0; i < gord; ++i) {
2337  std::cerr << (*subIter)[i] << " ";
2338  }
2339  std::cerr << "\n";
2340 #endif
2341  vector<unsigned short>::const_iterator siIter = (*subIter).begin();
2342  vector<unsigned short>::const_iterator gsIter = goodservers.begin();
2343  for (; gsIter != goodservers.end(); ++gsIter) {
2344  if (siIter != (*subIter).end() && *gsIter == *siIter) {
2345  ++siIter;
2346  } else {
2347  sub_goodservers.push_back(*gsIter);
2348  }
2349  }
2350 #ifdef VERBOSE_DP
2351  std::cerr << "\tsub_goodservers = ";
2352  for (unsigned int i = 0; i < n - gord; ++i) {
2353  std::cerr << sub_goodservers[i] << " ";
2354  }
2355  std::cerr << "\n";
2356 #endif
2357 
2358  FX L, B(0, 1);
2359  unsigned short numagree, numdisagree;
2360  vector<unsigned short> vecagree;
2361  test_interpolate(gord - 1, shares, indices, *subIter, goodservers, numagree, numdisagree, vecagree, L);
2362  for (unsigned int i = 0; i < gord; ++i) {
2363  FX mult(0, -(indices[(*subIter)[i]]));
2364  SetCoeff(mult, 1, 1);
2365  B *= mult;
2366  }
2367 
2368 #ifdef VERBOSE_DP
2369  std::cerr << "\tL(z) = " << L << "\n";
2370  std::cerr << "\tB(z) = " << B << "\n";
2371 #endif
2372 
2373  vec_F new_shares;
2374  new_shares.SetLength(shares.length());
2375  for (unsigned int i = 0; i < sub_goodservers.size(); ++i) {
2376  new_shares[sub_goodservers[i]] = (shares[sub_goodservers[i]] - eval(L, indices[sub_goodservers[i]])) / eval(B, indices[sub_goodservers[i]]);
2377  }
2378 
2379 #ifdef VERBOSE_DP
2380  std::cerr << "\tnew_shares =";
2381  for (int i = 0; i < new_shares.length(); ++i) {
2382  std::cerr << " " << new_shares[i];
2383  }
2384  std::cerr << "\n";
2385 #endif
2386 
2387  TestType testType = BEST;
2388  vector<RecoveryPoly<FX> > sub_polys = findpolys(ell - gord, h - gord, sub_goodservers, indices, new_shares, testType);
2389 
2390 #ifdef VERBOSE_DP
2391  std::cerr << "\tsub_polys =\n";
2392  for (unsigned int j = 0; j < sub_polys.size(); ++j) {
2393  std::cerr << "\t\t" << sub_polys[j].phi << ", { ";
2394  for (unsigned int i = 0; i < sub_polys[j].G.size(); ++i) {
2395  std::cerr << sub_polys[j].G[i] << " ";
2396  }
2397  std::cerr << "}\n";
2398  }
2399  std::cerr << "\tpolys +=\n";
2400 #endif
2401  typename vector<RecoveryPoly<FX> >::iterator rpIter;
2402  for (rpIter = sub_polys.begin(); rpIter != sub_polys.end(); ++rpIter) {
2403  soln_map[rpIter->phi * B + L].insert(rpIter->G.begin(), rpIter->G.end());
2404  }
2405 
2406  sub_goodservers.clear();
2407  ++subIter;
2408  }
2409 
2410  } else if (dptype == ASSUME_WRONG) {
2411 #ifdef VERBOSE_DP
2412  std::cerr << "ASSUME WRONG: g = " << gord << "\n";
2413 #endif
2414  assume_servers.insert(assume_servers.begin(), goodservers.begin(), goodservers.begin() + h + gord);
2415  subset_iterator subIter = subset_iterator(assume_servers, gord);
2416  while( ! subIter.atend() ) {
2417 #ifdef VERBOSE_DP
2418  std::cerr << "\t*subIter = ";
2419  for (unsigned int i = 0; i < gord; ++i) {
2420  std::cerr << (*subIter)[i] << " ";
2421  }
2422  std::cerr << "\n";
2423 #endif
2424  vector<unsigned short>::const_iterator siIter = (*subIter).begin();
2425  vector<unsigned short>::const_iterator gsIter = goodservers.begin();
2426  for (; gsIter != goodservers.end(); ++gsIter) {
2427  if (siIter != (*subIter).end() && *gsIter == *siIter) {
2428  ++siIter;
2429  } else {
2430  sub_goodservers.push_back(*gsIter);
2431  }
2432  }
2433 #ifdef VERBOSE_DP
2434  std::cerr << "\tsub_goodservers = ";
2435  for (unsigned int i = 0; i < n - gord; ++i) {
2436  std::cerr << sub_goodservers[i] << " ";
2437  }
2438  std::cerr << "\n";
2439 #endif
2440 
2441  TestType testType = BEST;
2442  vector<RecoveryPoly<FX> > sub_polys = findpolys(ell, h, sub_goodservers, indices, shares, testType);
2443 
2444 #ifdef VERBOSE_DP
2445  std::cerr << "\tsub_polys =\n";
2446  for (unsigned int j = 0; j < sub_polys.size(); ++j) {
2447  std::cerr << "\t\t" << sub_polys[j].phi << ", { ";
2448  for (unsigned int i = 0; i < sub_polys[j].G.size(); ++i) {
2449  std::cerr << sub_polys[j].G[i] << " ";
2450  }
2451  std::cerr << "}\n";
2452  }
2453  std::cerr << "\tpolys +=\n";
2454 #endif
2455  typename vector<RecoveryPoly<FX> >::iterator rpIter;
2456  for (rpIter = sub_polys.begin(); rpIter != sub_polys.end(); ++rpIter) {
2457  soln_map[rpIter->phi].insert(rpIter->G.begin(), rpIter->G.end());
2458  }
2459 
2460  sub_goodservers.clear();
2461  ++subIter;
2462  }
2463 
2464  } else if (dptype == ASSUME_SHARES) {
2465 #ifdef VERBOSE_DP
2466  std::cerr << "ASSUME SHARES: d = " << gord << "\n";
2467 #endif
2468  assume_servers.insert(assume_servers.begin(), goodservers.begin(), goodservers.begin() + gord);
2469  sub_goodservers.insert(sub_goodservers.begin(), goodservers.begin() + gord, goodservers.end());
2470 
2471  for (unsigned int r = 0; r <= gord && r <= ell + 1; ++r) {
2472  subset_iterator subIter = subset_iterator(assume_servers, r);
2473  while( ! subIter.atend() ) {
2474 #ifdef VERBOSE_DP
2475  std::cerr << "\t*subIter = ";
2476  for (unsigned int i = 0; i < r; ++i) {
2477  std::cerr << (*subIter)[i] << " ";
2478  }
2479  std::cerr << "\n";
2480 #endif
2481 
2482  FX L, B(0, 1);
2483  if (r != 0) {
2484  unsigned short numagree, numdisagree;
2485  vector<unsigned short> vecagree;
2486  test_interpolate(r - 1, shares, indices, *subIter, goodservers, numagree, numdisagree, vecagree, L);
2487  for (unsigned int i = 0; i < r; ++i) {
2488  FX mult(0, -(indices[(*subIter)[i]]));
2489  SetCoeff(mult, 1, 1);
2490  B *= mult;
2491  }
2492  } else {
2493  L = FX::zero();
2494  }
2495 
2496 #ifdef VERBOSE_DP
2497  std::cerr << "\tL(z) = " << L << "\n";
2498  std::cerr << "\tB(z) = " << B << "\n";
2499 #endif
2500 
2501  vec_F new_shares;
2502  new_shares.SetLength(shares.length());
2503  for (unsigned int i = 0; i < sub_goodservers.size(); ++i) {
2504  new_shares[sub_goodservers[i]] = (shares[sub_goodservers[i]] - eval(L, indices[sub_goodservers[i]])) / eval(B, indices[sub_goodservers[i]]);
2505  }
2506 
2507 #ifdef VERBOSE_DP
2508  std::cerr << "\tnew_shares =";
2509  for (int i = 0; i < new_shares.length(); ++i) {
2510  std::cerr << " " << new_shares[i];
2511  }
2512  std::cerr << "\n";
2513 #endif
2514 
2515  TestType testType = BEST;
2516  vector<RecoveryPoly<FX> > sub_polys = findpolys(ell - r, h - r, sub_goodservers, indices, new_shares, testType);
2517 
2518 #ifdef VERBOSE_DP
2519  std::cerr << "\tsub_polys =\n";
2520  for (unsigned int j = 0; j < sub_polys.size(); ++j) {
2521  std::cerr << "\t\t" << sub_polys[j].phi << ", { ";
2522  for (unsigned int i = 0; i < sub_polys[j].G.size(); ++i) {
2523  std::cerr << sub_polys[j].G[i] << " ";
2524  }
2525  std::cerr << "}\n";
2526  }
2527  std::cerr << "\tpolys +=\n";
2528 #endif
2529  typename vector<RecoveryPoly<FX> >::iterator rpIter;
2530  for (rpIter = sub_polys.begin(); rpIter != sub_polys.end(); ++rpIter) {
2531  soln_map[rpIter->phi * B + L].insert(rpIter->G.begin(), rpIter->G.end());
2532  }
2533 
2534  ++subIter;
2535  }
2536  }
2537  sub_goodservers.clear();
2538 
2539  } else {
2540 #ifdef VERBOSE_DP
2541  std::cerr << "FAIL: Invalid DPType\n";
2542 #endif
2543  return vector<RecoveryPoly<FX> >(); // FAIL
2544  }
2545 
2546  vector<RecoveryPoly<FX> > polys;
2547  typename map<FX, std::set<unsigned short>, cmpPolys<F,vec_F,FX,FXY,mat_F> >::iterator soln_iter;
2548  for (soln_iter = soln_map.begin(); soln_iter != soln_map.end(); ++soln_iter) {
2549  vector<unsigned short> new_G (soln_iter->second.begin(), soln_iter->second.end());
2550  polys.push_back(RecoveryPoly<FX>(new_G, soln_iter->first));
2551  }
2552  return polys;
2553 }
2554 
2555 
2556 template<class F, class vec_F, class FX, class FXY, class mat_F>
2557 vector< RecoveryPoly<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_best (
2558  unsigned int n, int ell,
2559  unsigned int h, const vector<unsigned short> &goodservers,
2560  const vec_F &indices, const vec_F &shares, TestType &testType, DPType &dpType,
2561  int &gord)
2562 {
2563 /*
2564  char buffer[64];
2565  char testTypeStr[16], dpTypeStr[16];
2566 
2567  std::stringstream cmd;
2568  cmd << "grep --color=never '^" << n << "," << ell << "," << h << ",' best.csv | cut --output-delimiter=' ' -d',' -f4,5,6";
2569 #ifdef VERBOSE_FINDPOLYS
2570  std::cerr << "cmd = " << cmd.str() << "\n";
2571 #endif
2572 
2573  FILE * f = popen(cmd.str().c_str(), "r");
2574  if (f == 0) {
2575 #ifdef VERBOSE_FINDPOLYS
2576  std::cerr << "FAIL: Could not read from best.csv\n";
2577 #endif
2578  return vector<RecoveryPoly<FX> >(); // FAIL
2579  }
2580  if (fgets(buffer, sizeof(buffer), f) != buffer) {
2581 #ifdef VERBOSE_FINDPOLYS
2582  std::cerr << "FAIL: Could not get data from command\n";
2583 #endif
2584  fclose(f);
2585  return vector<RecoveryPoly<FX> >(); // FAIL
2586  }
2587  fclose(f);
2588 
2589  int ret = 0;
2590  ret = sscanf(buffer, "%s %s %d", testTypeStr, dpTypeStr, &gord);
2591  if (ret != 1 && ret != 3) {
2592 #ifdef VERBOSE_FINDPOLYS
2593  std::cerr << "FAIL: Could not parse data from best.csv\n";
2594 #endif
2595  return vector<RecoveryPoly<FX> >(); // FAIL
2596  }
2597  for (unsigned int i = 2; i < MAX_TESTTYPE; ++i) {
2598  if (testTypeStr == testTypeStrings[i]) {
2599  testType = (TestType)(i);
2600  break;
2601  }
2602  }
2603 
2604  if (testType == DP) {
2605  for (unsigned int i = 1; i < MAX_DPTYPE; ++i) {
2606  if (dpTypeStr == DPTypeStrings[i]) {
2607  dpType = (DPType)(i);
2608  break;
2609  }
2610  }
2611  } else {
2612  dpType = UNDEFINED_DPTYPE;
2613  gord = 1;
2614  }
2615  */
2616 
2617  portfolioChoice(n, ell, h, testType, dpType, gord);
2618 
2619 #ifdef VERBOSE_FINDPOLYS
2620  std::cerr << "The best algoritm is:\n";
2621  std::cerr << " testType = " << testTypeStrings[testType] << "\n";
2622  std::cerr << " dpType = " << DPTypeStrings[dpType] << "\n";
2623  std::cerr << " gord = " << gord << "\n";
2624 #endif
2625 
2626  DPType usedDPType = dpType;
2627  vector<RecoveryPoly<FX> > polys = findpolys(ell, h, goodservers, indices, shares, testType, usedDPType, gord);
2628 
2629  return polys;
2630 }
2631 
2632 
2633 template<class F, class vec_F, class FX, class FXY, class mat_F>
2634 vector< RecoveryPoly<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys (int k,
2635  unsigned int t, const vector<unsigned short> &goodservers,
2636  const vec_F &indices, const vec_F &shares, TestType &testType, DPType &dpType, int &gord)
2637 {
2638  unsigned int n = goodservers.size();
2639 
2640 #ifdef VERBOSE_DP
2641  std::cerr << "RUNNING findpolys WITH (" << testTypeStrings[testType] << ", " << n << ", " << k << ", " << t << ")\n";
2642 #endif
2643 
2644  vector<RecoveryPoly<FX> > polys;
2645  switch(testType) {
2646  case BEST:
2647  polys = findpolys_best(n, k, t, goodservers, indices, shares, testType, dpType, gord);
2648  break;
2649  case BRUTE:
2650  polys = findpolys_brute(k, t, goodservers, indices, shares);
2651  break;
2652  case KOTTER:
2653  case CH_MS:
2654  polys = findpolys_gs(k, t, goodservers, indices, shares, testType);
2655  break;
2656  case BW:
2657  polys = findpolys_bw(k, t, goodservers, indices, shares);
2658  break;
2659  case DP:
2660  polys = findpolys_dp(k, t, goodservers, indices, shares, dpType, gord);
2661  break;
2662  case CH_MULTI:
2663  case CH_TK1:
2664 #ifdef VERBOSE_FINDPOLYS
2665  std::cerr << "FAIL: Invalid single poly test type\n";
2666 #endif
2667  return vector<RecoveryPoly<FX> >(); // FAIL
2668  break;
2669  case UNDEFINED:
2670  case UNKNOWN:
2671  case MAX_TESTTYPE:
2672  default:
2673 #ifdef VERBOSE_FINDPOLYS
2674  std::cerr << "FAIL: Not a valid test type\n";
2675 #endif
2676  return vector<RecoveryPoly<FX> >(); // FAIL
2677  break;
2678  }
2679 
2680  (void)n;
2681  return polys;
2682 }
2683 
2684 template<class F, class vec_F, class FX, class FXY, class mat_F>
2685 vector< RecoveryPolyMulti<FX> > RSDecoder<F,vec_F,FX,FXY,mat_F>::findpolys_multi (unsigned int k,
2686  unsigned int t, const vector<unsigned short> &goodservers,
2687  const vec_F &indices, const vector<vec_F> &shares, TestType testType)
2688 {
2689  unsigned int n = goodservers.size();
2690  unsigned int m = shares.size();
2691 
2692  vector<RecoveryPolyMulti<FX> > multipolys;
2693  vector<RecoveryPoly<FX> > polys;
2694  switch(testType) {
2695 
2696  case BEST:
2697  case BRUTE:
2698  case KOTTER:
2699  case CH_MS:
2700  case BW:
2701 #ifdef VERBOSE_FINDPOLYS
2702  std::cerr << "FAIL: Invalid multi poly test type\n";
2703 #endif
2704  return vector<RecoveryPolyMulti<FX> >(); // FAIL
2705  break;
2706 
2707  case CH_MULTI:
2708 #ifdef VERBOSE_FINDPOLYS
2709  std::cerr << "FAIL: The test type CH_MULTI is not implemented\n";
2710 #endif
2711  return vector<RecoveryPolyMulti<FX> >(); // FAIL
2712  break;
2713 
2714  case CH_TK1:
2715  multipolys = findpolys_ch_tk1(k, t, m, goodservers, indices, shares);
2716  break;
2717 
2718  case UNDEFINED:
2719  case UNKNOWN:
2720  case MAX_TESTTYPE:
2721  default:
2722 #ifdef VERBOSE_FINDPOLYS
2723  std::cerr << "Invalid test type!\n";
2724 #endif
2725  return vector<RecoveryPolyMulti<FX> >(); // Fail
2726  }
2727 
2728  (void)n;
2729  return multipolys;
2730 }
2731 
2732 
2733 template <class F, class vec_F, class FX>
2734 void addResult (vector<DecoderResult<F> > &results, nservers_t h,
2735  dbsize_t word_number, vector<RecoveryPoly<FX> > polys, const vec_F &interp_indices)
2736 {
2737  typename vector<RecoveryPoly<FX> >::iterator poly_iter;
2738  if (results.empty()) {
2739  for (poly_iter = polys.begin(); poly_iter != polys.end(); ++poly_iter) {
2740  if (poly_iter->G.size() >= h) {
2741  vector<map<dbsize_t, F> > new_recovered_vec;
2742  F wz;
2743  if (interp_indices.length() != 0){
2744  for (int i=0; i<interp_indices.length(); i++) {
2745  map<dbsize_t, F> new_recovered;
2746  eval(wz, poly_iter->phi, interp_indices[i]);
2747  new_recovered[word_number] = wz;
2748  new_recovered_vec.push_back(new_recovered);
2749  }
2750  } else {
2751  map<dbsize_t, F> new_recovered;
2752  eval(wz, poly_iter->phi, F::zero());
2753  new_recovered[word_number] = wz;
2754  new_recovered_vec.push_back(new_recovered);
2755  }
2756 
2757  results.push_back(DecoderResult<F>(poly_iter->G, new_recovered_vec));
2758  }
2759  }
2760  return;
2761  }
2762 
2763  if (results.size() > 0 && results[0].recovered.size() > 0 &&
2764  results[0].recovered[0].find(word_number) != results[0].recovered[0].end()) {
2765 #ifdef VERBOSE_RECOVER
2766  std::cerr << "This one is already done!\n";
2767 #endif
2768  return;
2769  }
2770 
2771  ssize_t result_size = results.size();
2772  ssize_t num_interp_indices = interp_indices.length();
2773  for (ssize_t idx=0; idx < result_size; ++idx) {
2774  vector<nservers_t> orig_G = results[idx].G;
2775 
2776  // Ensure the recovered field of the DecoderResult results[idx]
2777  // is of the right length
2778  results[idx].recovered.resize(num_interp_indices > 0 ?
2779  num_interp_indices : 1);
2780 
2781  ssize_t found = -1;
2782  for (poly_iter = polys.begin(); poly_iter != polys.end(); ++poly_iter) {
2783  vector<nservers_t> intersection = intersect(poly_iter->G, orig_G);
2784  if (intersection.size() >= h) {
2785  F wz;
2786  if (found == -1) {
2787  results[idx].G = intersection;
2788  if (num_interp_indices != 0) {
2789  for (int sub_query = 0; sub_query < num_interp_indices; sub_query++) {
2790  eval(wz, poly_iter->phi, interp_indices[sub_query]);
2791  results[idx].recovered[sub_query][word_number] = wz;
2792  }
2793  } else {
2794  eval(wz, poly_iter->phi, F::zero());
2795  results[idx].recovered[0][word_number] = wz;
2796  }
2797  found = idx;
2798  } else {
2799  results.push_back(DecoderResult<F>(intersection,
2800  results[idx].recovered));
2801  if (num_interp_indices != 0) {
2802  for (int sub_query = 0; sub_query < num_interp_indices; sub_query++) {
2803  eval(wz, poly_iter->phi, interp_indices[sub_query]);
2804  results[results.size()-1].recovered[sub_query][word_number] = wz;
2805  }
2806  } else {
2807  eval(wz, poly_iter->phi, F::zero());
2808  results[results.size()-1].recovered[0][word_number] = wz;
2809  }
2810  }
2811  }
2812  }
2813  if (found == -1) {
2814  results.erase(results.begin()+idx);
2815  --idx;
2816  --result_size;
2817  }
2818  }
2819 }
2820 
2821 
2822 template<class F, class vec_F, class FX, class FXY, class mat_F>
2823 bool RSDecoder<F,vec_F,FX,FXY,mat_F>::Recover (dbsize_t bytes_per_word,
2824  nservers_t t, nservers_t h, const vector<nservers_t> &goodservers,
2825  const vector<vector<vec_F> > &values, const vec_F &server_indices,
2826  vector<vector<DecoderResult<F> > > &results,
2827  vector<std::set<dbsize_t> > &decoded,
2828  const vector<vec_F> &vecs_interp_indices, const nqueries_t multi_only)
2829 {
2830 #ifdef VERBOSE_RECOVER
2831  // std::cerr << "h = " << h << "\n";
2832 #endif
2833  TestType ttype;
2834  nservers_t k = goodservers.size();
2835  nservers_t maxdeg = t;
2836 
2837  // Keep track of undecoded words by query
2838  map<nqueries_t, std::set<dbsize_t> > undecoded;
2839 
2840  nqueries_t num_queries = values.size();
2841  for (nqueries_t q = 0; q < num_queries; ++q) {
2842  undecoded[q] = std::set<dbsize_t>();
2843  dbsize_t num_words = values[q].size();
2844  nqueries_t qbs = vecs_interp_indices[q].length();
2845  if (qbs == 0) {
2846  qbs = 1;
2847  }
2848  if (maxdeg < t + qbs - 1) {
2849  maxdeg = t + qbs - 1;
2850  }
2851  for (dbsize_t i = 0; i < num_words; ++i) {
2852 #ifdef VERBOSE_RECOVER
2853  std::cerr << "Decoding (" << q << ", " << i << "):\n";
2854  std::cerr << " (k, t, h) = (" << k << ", " << t << ", " << h <<
2855  ")\n";
2856  std::cerr << " vii[q] = " << vecs_interp_indices[q] << "\n";
2857  std::cerr << " qbs = " << qbs << "\n";
2858 #endif
2859  if (decoded[q].find(i) != decoded[q].end()) {
2860 #ifdef VERBOSE_RECOVER
2861  std::cerr << " Already decoded.\n";
2862 #endif
2863  continue;
2864  }
2865 
2866  if (q >= multi_only) {
2867  // Try EasyRecover
2868  bool easy_result = EasyRecover(bytes_per_word, t+qbs-1, h, results[q], i,
2869  values[q][i], server_indices, vecs_interp_indices[q]);
2870  if (easy_result) {
2871 #ifdef VERBOSE_RECOVER
2872  std::cerr << " EASY: PASS\n";
2873 #endif
2874  decoded[q].insert(i);
2875  continue;
2876  }
2877 #ifdef VERBOSE_RECOVER
2878  std::cerr << " EASY: FAIL\n";
2879 #endif
2880 
2881  // Try Berlekamp-Welch
2882  ttype = BW;
2883  vector<RecoveryPoly<FX> > bw_result = findpolys(t+qbs-1, h, goodservers, server_indices, values[q][i], ttype);
2884  if (bw_result.size() > 0) {
2885 #ifdef VERBOSE_RECOVER
2886  std::cerr << " BW: PASS\n";
2887 #endif
2888  addResult<F,vec_F,FX>(results[q], h, i, bw_result, vecs_interp_indices[q]);
2889  decoded[q].insert(i);
2890  continue;
2891  }
2892 #ifdef VERBOSE_RECOVER
2893  std::cerr << " BW: FAIL\n";
2894 #endif
2895 
2896  // Try findpolys_best
2897  ttype = BEST;
2898  // Only run best in single-polynomial decoding realm or when tk1
2899  // can't give an answer (h == t+qbs)
2900  if (h > sqrt(k*(t+qbs-1)) || h == t+qbs) {
2901  vector<RecoveryPoly<FX> > best_result = findpolys(t+qbs-1, h, goodservers, server_indices, values[q][i], ttype);
2902  if (best_result.size() > 0) {
2903 #ifdef VERBOSE_RECOVER
2904  std::cerr << " BEST: PASS (#results: " << best_result.size() << ")\n";
2905  for (size_t iw=0;iw<best_result.size(); ++iw) {
2906  std::cerr << " " << best_result[iw].phi << "\n";
2907  }
2908 #endif
2909  addResult<F,vec_F,FX>(results[q], h, i, best_result, vecs_interp_indices[q]);
2910  decoded[q].insert(i);
2911  continue;
2912  }
2913 #ifdef VERBOSE_RECOVER
2914  std::cerr << " BEST: FAIL\n";
2915 #endif
2916  }
2917  }
2918 
2919  // Save for multi
2920 #ifdef VERBOSE_RECOVER
2921  std::cerr << " Saving for multi...\n";
2922 #endif
2923  undecoded[q].insert(i);
2924  }
2925  if (undecoded[q].empty()) {
2926 #ifdef VERBOSE_RECOVER
2927  std::cerr << "Query " << q << " is done\n";
2928 #endif
2929  undecoded.erase(q);
2930  }
2931  }
2932 
2933  // Check if done
2934  if (undecoded.empty()) {
2935 #ifdef VERBOSE_RECOVER
2936  std::cerr << "All queries are done\n";
2937 #endif
2938  return true;
2939  }
2940 
2941  // If there are enough for tk1, do tk1
2942  double queries_needed = (double)(k - h) / (double)(h - maxdeg - 1);
2943 #ifdef VERBOSE_RECOVER
2944  std::cerr << "queries_needed = " << queries_needed << "\n";
2945 #endif
2946 
2947  // Do multi while we have enough queries
2948  vector<nqueries_t> ud_queries;
2949  vector<typename std::set<dbsize_t>::iterator> ud_iters;
2950  map<nqueries_t, std::set<dbsize_t> >::iterator ud_iter;
2951  for (ud_iter = undecoded.begin(); ud_iter != undecoded.end(); ++ud_iter) {
2952  ud_queries.push_back(ud_iter->first);
2953  ud_iters.push_back(ud_iter->second.begin());
2954  }
2955  while (ud_queries.size() >= queries_needed) {
2956  vector<vec_F> multi_values;
2957  for (nqueries_t i = 0; i < ud_queries.size(); ++i) {
2958  //for (ud_iter = undecoded.begin(); ud_iter != undecoded.end(); ++ud_iter) {
2959  nqueries_t q = ud_queries[i];
2960  dbsize_t w = *(ud_iters[i]);
2961  multi_values.push_back(values[q][w]);
2962  }
2963  ttype = CH_TK1;
2964  vector<RecoveryPolyMulti<FX> > multi_result = findpolys_multi(maxdeg, h, goodservers, server_indices, multi_values, ttype);
2965 
2966  if (multi_result.size() == 0) {
2967 #ifdef VERBOSE_RECOVER
2968  std::cerr << " TK1: FAIL\n";
2969 #endif
2970  for (nqueries_t i = 0; i < ud_queries.size(); ++i) {
2971  ++(ud_iters[i]);
2972  }
2973  } else {
2974 #ifdef VERBOSE_RECOVER
2975  std::cerr << " TK1: PASS\n";
2976 #endif
2977 
2978  for (nqueries_t i = 0; i < ud_queries.size(); ++i) {
2979  //for (ud_iter = undecoded.begin(), i = 0; ud_iter != undecoded.end(); ++ud_iter, ++i) {
2980  nqueries_t q = ud_queries[i];
2981  dbsize_t w = *(ud_iters[i]);
2982  ++(ud_iters[i]);
2983  vector<RecoveryPoly<FX> > ith_result;
2984  typename vector<RecoveryPolyMulti<FX> >::iterator iter;
2985  for (iter = multi_result.begin(); iter != multi_result.end();
2986  ++iter) {
2987  ith_result.push_back(RecoveryPoly<FX>(iter->G, iter->phis[i]));
2988  }
2989  addResult<F,vec_F,FX>(results[q], h, w, ith_result, vecs_interp_indices[q]);
2990  decoded[q].insert(w);
2991  undecoded[q].erase(w);
2992  }
2993  }
2994 
2995  for (nqueries_t i = 0; i < ud_queries.size(); ++i) {
2996  //for (ud_iter = undecoded.begin(); ud_iter != undecoded.end(); ++ud_iter) {
2997  nqueries_t q = ud_queries[i];
2998  if (ud_iters[i] == undecoded[q].end()) {
2999  //if (w >= ud_iter->second.size()) {
3000 #ifdef VERBOSE_RECOVER
3001  if (undecoded[q].empty()) {
3002  undecoded.erase(q);
3003  std::cerr << "Query " << q << " is done\n";
3004  } else {
3005  std::cerr << "Query " << q << " was not fully decoded\n";
3006  }
3007 #endif
3008  ud_queries.erase(ud_queries.begin() + i);
3009  ud_iters.erase(ud_iters.begin() + i);
3010  --i;
3011  }
3012  }
3013  }
3014 
3015  // Check if done
3016  if (undecoded.empty()) {
3017 #ifdef VERBOSE_RECOVER
3018  std::cerr << "All queries are done\n";
3019 #endif
3020  return true;
3021  }
3022 #ifdef VERBOSE_RECOVER
3023  std::cerr << "NOT all queries were decoded\n";
3024 #endif
3025  return false;
3026 }
3027 
3028 
3029 // Depth-first search on the tree of coefficients; used by the
3030 // Roth-Ruckenstein algorithm.
3031 template<class F, class vec_F, class FX, class FXY, class mat_F>
3032 void RSDecoder<F,vec_F,FX,FXY,mat_F>::dfs(vector<FX> &res,
3033  int u,
3034  vector<int> &pi,
3035  vector<int> &Deg,
3036  vector<F> &Coeff,
3037  vector<FXY> &Q,
3038  int &t,
3039  int degreebound)
3040 {
3041 #ifdef TEST_RR
3042  cout << "\nVertex " << u << ": pi[" << u << "] = " << pi[u] <<
3043  ", deg[" << u << "] = " << Deg[u] << ", Coeff[" << u <<
3044  "] = " << Coeff[u] << "\n";
3045  cout << "Q[" << u << "] = " << Q[u] << "\n";
3046 #endif
3047  // if Q_u(x,0) == 0 then output y-root
3048  if ( IsZero(Q[u]) || IsZero(Q[u].rep[0])) {
3049  // Output f_u[x]
3050 
3051  FX fux;
3052  while (Deg[u] >= 0) {
3053  SetCoeff(fux, Deg[u], Coeff[u]);
3054  u = pi[u];
3055  }
3056 #ifdef TEST_RR
3057  cout << "Outputting " << fux << "\n";
3058 #endif
3059  res.push_back(fux);
3060  } else if (degreebound < 0 || Deg[u] < degreebound) {
3061  // Construct Q_u(0,y)
3062  FX Qu0y;
3063  int degqu = deg(Q[u]);
3064  for (int d = 0; d <= degqu; ++d) {
3065  SetCoeff(Qu0y, d, coeff(Q[u].rep[d], 0));
3066  }
3067 
3068 #ifdef TEST_RR
3069  cout << "Q[" << u << "](0,y) = " << Qu0y << "\n";
3070 #endif
3071  // Find its roots
3072  vec_F rootlist =
3073  findroots_FX<F,vec_F,FX,
3074  typename DT::vec_FX,typename DT::vec_pair_FX_long>(Qu0y);
3075 #ifdef TEST_RR
3076  cout << "Rootlist = " << rootlist << "\n";
3077 #endif
3078  int numroots = rootlist.length();
3079  for (int r=0; r<numroots; ++r) {
3080  // For each root a, recurse on <<Q[u](x, x*y + a)>>
3081  // where <<Q>> is Q/x^k for the maximal k such that the
3082  // division goes evenly.
3083  int v = t;
3084  ++t;
3085  pi.push_back(u);
3086  Deg.push_back(Deg[u]+1);
3087  Coeff.push_back(rootlist[r]);
3088  // mapit(Q(x,y), a) computes <<Q(x, x*y + a)>>
3089  Q.push_back(mapit(Q[u], rootlist[r]));
3090  dfs(res, v, pi, Deg, Coeff, Q, t, degreebound);
3091  }
3092  }
3093 }
3094 
3095 // Return a list of roots for y of the bivariate polynomial P(x,y).
3096 // If degreebound >= 0, only return those roots with degree <=
3097 // degreebound. This routine only works over fields F.
3098 template<class F, class vec_F, class FX, class FXY, class mat_F>
3100  const FXY &P, int degreebound)
3101 {
3102  vector<int> pi;
3103  vector<int> Deg;
3104  vector<F> Coeff;
3105  vector<FXY> Q;
3106  vector<FX> res;
3107  int t = 1;
3108 
3109 #ifdef TEST_RR
3110  std::cerr << "Now in findroots(" << P << ", " << degreebound << ")\n";
3111 #endif
3112 
3113  FXY P0 = backShiftX(P, minX(P));
3114  pi.push_back(-1);
3115  Deg.push_back(-1);
3116  Coeff.push_back(F::zero());
3117  Q.push_back(P0);
3118  int u = 0;
3119 
3120  if (degreebound < 0) {
3121  degreebound = degX(P0);
3122  }
3123  dfs(res, u, pi, Deg, Coeff, Q, t, degreebound);
3124 
3125  return res;
3126 }
3127 
3128 
3129 // Return a list of roots for y of the bivariate polynomial P(x,y).
3130 // If degreebound >= 0, only return those roots with degree <=
3131 // degreebound. This routine handles the case where F is the
3132 // integers mod p1*p2 as well as fields. (But it handles the ring case
3133 // in a specialization of this templated method.) This routine may alsofromsage[*rowIter][i];
3134 // return some spurious values.
3135 template<class F, class vec_F, class FX, class FXY, class mat_F>
3136 vector<FX> RSDecoder<F,vec_F,FX,FXY,mat_F>::findroots(const FXY &P, int degreebound)
3137 {
3138 // std::cerr << "P = " << P << "\n";
3139  vector<FX> result = rr_findroots(P, degreebound);
3140 // for (unsigned int i = 0; i < result.size(); ++i) {
3141 // std::cerr << "result[" << i << "] = " << result[i] << "\n";
3142 // }
3143  return result;
3144 }
3145 
3146 #endif
3147 
Definition: subset_iter.h:37
Definition: rsdecoder_impl.h:2293
Reed-Solomon Decoder.
Definition: rsdecoder.h:161
A struct containing a reconstructed polynomial over the field F.
Definition: rsdecoder.h:57
Contains the results (so far) of decoding words.
Definition: rsdecoder.h:87
bool Recover(dbsize_t bytes_per_word, nservers_t t, nservers_t h, const vector< nservers_t > &goodservers, const vector< vector< vec_F > > &values, const vec_F &server_indices, vector< vector< DecoderResult< F > > > &results, vector< std::set< dbsize_t > > &decoded, const vector< vec_F > &vec_interp_indices, const nqueries_t multi_only=0)
The main method to do the Reed-Solomon Decoding.
Definition: rsdecoder_impl.h:2823
Definition: FXY.h:53
static void test_interpolate(unsigned short t, const vec_F &values, const vec_F &indices, const vector< unsigned short > &I, const vector< unsigned short > &G, unsigned short &numagree, unsigned short &numdisagree, vector< unsigned short > &vecagree, FX &phi)
Interpolate some points I and check how many points G agree with the result.
Definition: rsdecoder_impl.h:84
A struct containing a multiple reconstructed polynomials over the field F.
Definition: rsdecoder.h:72