Percy++
A C++ implementation of Private Information Retrieval (PIR) protocols
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Pages
rsdecoder.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 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of version 2 of the GNU General Public License as
8 // published by the Free Software Foundation.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // There is a copy of the GNU General Public License in the COPYING file
16 // packaged with this plugin; if you cannot find it, write to the Free
17 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 
20 #ifndef __GSDECODER_H__
21 #define __GSDECODER_H__
22 
23 #include <vector>
24 #include <map>
25 #include <set>
26 #include <string>
27 #include <NTL/mat_ZZ_p.h>
28 #include <NTL/mat_GF2E.h>
29 #include "percyresult.h"
30 #include "FXY.h"
31 #include "portfolio.h"
32 
33 // An implementation of the Guruswami-Sudan decoder. This decoder will
34 // produce all possible codewords of degree at most t that match the
35 // given codeword with k non-erasures in more than sqrt(k*t) places.
36 //
37 // It runs in polynomial time, but in the worst case, it's O(k^12).
38 // Luckily, the worst case is when t=k-2, which is easily solved by
39 // brute force. (You will need to do this brute force outside this
40 // class.)
41 //
42 // This implementation is based on the K\"otter and Roth-Ruckenstein
43 // algorithms, as described in: R. J. McEliece. The Guruswami-Sudan
44 // Decoding Algorithm for Reed-Solomon Codes. IPN Progress Report
45 // 42-153, May 15, 2003.
46 // http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
47 
48 NTL_CLIENT
49 
50 // Note: In most places in this file, F (which is usually a field ZZ_p
51 // or GF2E) may also be a ring ZZ_p modulo a product of two large
52 // primes.
53 
56 template <class FX>
57 struct RecoveryPoly {
61  RecoveryPoly(vector<nservers_t> G, FX phi) : G(G), phi(phi) {}
62 
64  vector<nservers_t> G;
66  FX phi;
67 };
68 
71 template <class FX>
76  RecoveryPolyMulti(vector<nservers_t> G, vector<FX> phis) : G(G), phis(phis) {}
77 
79  vector<nservers_t> G;
81  vector<FX> phis;
82 };
83 
86 template <class F>
87 struct DecoderResult {
91  DecoderResult (vector<nservers_t> G, vector<map<dbsize_t, F> > recovered) :
92  G(G), recovered(recovered) {}
93 
95  vector<nservers_t> G;
97  vector<map<dbsize_t, F> > recovered;
98 };
99 
100 
101 // A class for caching the results of C() computations. Note that you
102 // need to keep a separate Ccache around for each different field you
103 // work in.
104 
105 typedef pair<unsigned int, unsigned int> pairint;
106 #define Ccache_t map<pairint, F>
107 
108 template <class F>
109 static F C(Ccache_t &Ccache, unsigned int n, unsigned int k)
110 {
111  // Do we already know the answer to this one?
112  pairint nk;
113  nk.first = n;
114  nk.second = k;
115  typename Ccache_t::const_iterator Ci = Ccache.find(nk);
116  if (Ci != Ccache.end()) {
117  // Yes; return it
118  return Ci->second;
119  }
120 
121  // Calculate in ZZ in case we're working in a low-characteristic
122  // field.
123  ZZ num, dem;
124  num = 1;
125  dem = 1;
126  unsigned int i;
127 
128  for (i=0;i<k;++i) {
129  num *= (n-i);
130  dem *= (k-i);
131  }
132 
133  num /= dem;
134 
135  // Now convert it into the right field, cache the answer, and return
136  // it
137  F res;
138  conv(res, num);
139  Ccache[nk] = res;
140  return res;
141 }
142 
143 
144 // Comparison functions used to let polynomials be keys for maps
145 bool cmp (const GF2EX& a, const GF2EX& b);
146 bool cmp (const ZZ_pX& a, const ZZ_pX& b);
147 
148 
152 // It's been tested on ZZ_p and GF2E. I haven't tried it over
153 // ZZ_pE, but I don't know why it wouldn't work there too; it should
154 // only be necessary to specialize DT (see below) appropriately.
160 template <class F, class vec_F, class FX, class FXY, class mat_F>
161 class RSDecoder {
162  public:
167 
171  RSDecoder(const ZZ &p1, const ZZ &p2): p1(p1), p2(p2) {}
172 
199  bool Recover (dbsize_t bytes_per_word, nservers_t t, nservers_t h,
200  const vector<nservers_t> &goodservers, const vector<vector<vec_F> > &values,
201  const vec_F &server_indices, vector<vector<DecoderResult<F> > > &results,
202  vector<std::set<dbsize_t> > &decoded,
203  const vector<vec_F> &vec_interp_indices,
204  const nqueries_t multi_only = 0);
205 
212  static string append(const string &s, const F &wz,
213  unsigned int bytes_per_word);
214 
232  static void test_interpolate(unsigned short t,
233  const vec_F &values, const vec_F &indices,
234  const vector<unsigned short> &I,
235  const vector<unsigned short> &G,
236  unsigned short &numagree, unsigned short &numdisagree,
237  vector<unsigned short> &vecagree, FX &phi);
238 
239 #ifdef TEST_RR
240  public:
241 #else
242  private:
243 #endif
244  // Return a list of roots for y of the bivariate polynomial
245  // P(x,y). If degreebound >= 0, only return those roots with
246  // degree <= degreebound. This routine handles the case where F
247  // is the integers mod p1*p2 as well as fields. This routine
248  // may also return some spurious values, so you need to validate
249  // the answers it gives.
250  //
251  // This is an implementation of the Roth-Ruckenstein algorithm
252  // for finding roots of bivariate polynomials, as explained in
253  // section IX of: R. J. McEliece. The Guruswami-Sudan Decoding
254  // Algorithm for Reed-Solomon Codes. IPN Progress Report 42-153,
255  // May 15, 2003.
256  // http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
257  vector<FX> findroots(const FXY &P, int degreebound);
258 
259 #if defined(TEST_FINDPOLYS) || defined(TIME_FINDPOLYS)
260  public:
261 #else
262  private:
263 #endif
264 
265  // findpolys wrapper function
266  vector< RecoveryPoly<FX> > findpolys(int k,
267  unsigned int t, const vector<unsigned short> &goodservers,
268  const vec_F &indices, const vec_F &shares, TestType &testType, DPType
269  &dpType, int &gord);
270  vector< RecoveryPoly<FX> > findpolys(int k,
271  unsigned int t, const vector<unsigned short> &goodservers,
272  const vec_F &indices, const vec_F &shares, TestType &testType)
273  {
274  DPType dptype; int gord;
275  return findpolys(k, t, goodservers, indices, shares, testType, dptype,
276  gord);
277  }
278  vector< RecoveryPoly<FX> > findpolys(int k,
279  unsigned int t, const vector<unsigned short> &goodservers,
280  const vec_F &indices, const vec_F &shares)
281  {
282  TestType testtype; DPType dptype; int gord;
283  return findpolys(k, t, goodservers, indices, shares, testtype, dptype,
284  gord);
285  }
286 
287  // Portfolio algorithm for single-polynomial decoding
288  vector< RecoveryPoly<FX> > findpolys_best(unsigned int n, int ell,
289  unsigned int h, const vector<unsigned short> &goodservers,
290  const vec_F &indices, const vec_F &shares, TestType &testType,
291  DPType &dpType, int &gord);
292 
293  // Wrapper for multi-polynomial decoding
294  vector< RecoveryPolyMulti<FX> > findpolys_multi(unsigned int k,
295  unsigned int t, const vector<unsigned short> &goodservers,
296  const vec_F &indices, const vector<vec_F> &shares, TestType testType = CH_TK1);
297 
298  // Use the K\"otter algorithm (below) to construct an
299  // appropriate bivariate polynomial and use the
300  // Roth-Ruckenstein algorithm (above) to extract its roots.
301  // Filter the results of the above to end up with just the
302  // answers we're looking for.
303  vector< RecoveryPoly<FX> > findpolys_gs(unsigned int k, unsigned int t,
304  const vector<unsigned short> &goodservers,
305  const vec_F& indices, const vec_F& shares, TestType testType = KOTTER);
306 
307  // Find all polynomials of degree at most k that agree with the
308  // given (index,share) pairs at at least t of the n points.
309  // This version simply uses brute force and interpolates all
310  // subsets of size k+1 of the n points. Note that in general,
311  // this version does *not* run in polynomial time, but for some
312  // cases (with n-k small, for example) it is faster than
313  // Guruswami-Sudan.
314  //
315  vector<RecoveryPoly<FX> > findpolys_brute(
316  int k_signed, unsigned int t,
317  const vector<unsigned short> &goodservers,
318  const vec_F &indices, const vec_F &shares);
319 
320  // Find a polynomial of degree ell that agrees with at least h shares. Uses
321  // the Berlekamp-Welch algorithm. This algorithm is only guaranteed to work
322  // when 2h > n + ell.
323  vector<RecoveryPoly<FX> > findpolys_bw(
324  unsigned int ell, unsigned int h,
325  const vector<unsigned short> &goodservers,
326  const vec_F &indices, const vec_F &shares);
327 
328  // A dynamic programming approach to decoding. We can assume that some
329  // servers are correct, some are wrong or a combination of the two
330  vector<RecoveryPoly<FX> > findpolys_dp (unsigned int ell, unsigned int h,
331  const vector<unsigned short> &goodservers,
332  const vec_F &indices, const vec_F &shares,
333  const DPType, unsigned int gord);
334 
335 #ifdef INCLUDE_GENERAL_MULTI
336  // (Needed for findpolys_ch_multi)
337  vector<map<unsigned int, FX> > solve_partial_solution (
338  unsigned int ell, unsigned int h, map<unsigned int, FX> partial,
339  const vector<vector<FX> >& rows, vector<unsigned int> row_order,
340  const vector<vector<unsigned int> >& order_of_expts);
341 
342  // The general Cohn-Heninger multi-polynomial decoding algorithm as
343  // described in "Approximate common divisors via lattices." (2011)
344  vector<RecoveryPolyMulti<FX> > findpolys_ch_multi(
345  unsigned int ell, unsigned int h, unsigned int m, unsigned int& t,
346  unsigned int& k,
347  const vector<unsigned short> &goodservers,
348  const vec_F &indices, const vector<vec_F> &shares);
349 #endif
350 
351  // The linear version of the Cohn-Heninger multi-polynomial decoding
352  // algorithm as described in "Approximate common divisors via lattices."
353  // (2011). This is the general algorithm with t=k=1.
354  vector<RecoveryPolyMulti<FX> > findpolys_ch_tk1(
355  unsigned int ell, unsigned int h, unsigned int m,
356  const vector<unsigned short> &goodservers,
357  const vec_F &indices, const vector<vec_F> &shares);
358 
359  // Solve the linear system of equations Ax=b
360  vector<FX> solve_linsys_FX (vector<vector<FX> >& A, vector<FX>& b,
361  unsigned int modulus = 0);
362 
363  private:
364  // A structure for holding derived types. It needs to be
365  // manually specialized for every kind of base field (ZZ_p,
366  // GF2E, etc.) we may want to work in.
367  struct DT {};
368 
369  // Construct a bivariate polynomial P(x,y) such that, for any
370  // polynomial f(x) of degree at most v that agrees with at least
371  // t of the given points, (y-f(x)) is a factor of P(x,y). This
372  // version is K"otter's Interpolation Algorithm, as described in
373  // Section VII of R. J. McEliece. The Guruswami-Sudan Decoding
374  // Algorithm for Reed-Solomon Codes. IPN Progress Report 42-153,
375  // May 15, 2003.
376  // http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
377  FXY interpolate_kotter(unsigned int v, unsigned int t,
378  const vector<unsigned short> &goodservers,
379  const vec_F &indices, const vec_F &shares);
380 
381 private:
382  // Construct a bivariate polynomial Q(x,y) such that, for any
383  // polynomial g(x) of degree at most ell that agrees with at least
384  // h of the given points, (y-g(x)) is a factor of Q(x,y). This
385  // version is Cohn and Heninger's improvement on the Guruswami-Sudan
386  // Decoding Algorithm as described in sections 1.2, 2.2 and 4 of
387  // Cohn, H. and Heninger, N. Ideal forms of Coppersmith's theorem and
388  // Guruswami-Sudan list decoding. August 6, 2010.
389  FXY interpolate_cohn_heninger(unsigned int v, unsigned int h,
390  const vector<unsigned short> &goodservers,
391  const vec_F &indices, const vec_F &shares);
392 
393  // Perform lattice basis reduction on a lattice with m basis vectors in F[z].
394  // The lattice is represented by a vector 'lattice' in (F[z][x])^m such that
395  // the coefficient vectors of each element in 'lattice' is a basis for the
396  // lattice. The result is a polynomial in F[z][x] whose coefficient vector
397  // is the smallest vector in the lattice. This implementation uses the
398  // algorithm found in Mulders, T. and Storjohann, A. On Lattice Reduction for
399  // Polynomial Matrices. December 2000.
400  vector<vector<FX> > reduce_lattice_MS(vector<vector<FX> > lattice,
401  // The auxiliary matrix must have the same number of rows as lattice
402  // If not, no operations will be performed on aux.
403  vector<vector<FX> >& aux,
404  const int reduceTo = -1, const unsigned int reduceNumber = 1);
405 
406  FXY reduce_lattice_opt(vector<FXY> lattice, const unsigned int n,
407  const unsigned int ell, const unsigned int k);
408 
409  // Evaluate the (r,s)th Hasse mixed partial derivative of g at
410  // the point (alpha, beta), which is:
411  // \sum_{i,j} C(i,r) C(j,s) a_{i,j} alpha^{i-r} beta^{j-s}
412  // = \sum_j C(j,s) beta^{j-s} \sum_i C(i,r) a_{i,j} alpha^{i-r}
413  // where g(x,y) = \sum_{i,j} a_{i,j} x^i y^j
414  // See page 14 of R. J. McEliece. The Guruswami-Sudan Decoding
415  // Algorithm for Reed-Solomon Codes. IPN Progress Report 42-153,
416  // May 15, 2003.
417  // http://citeseer.ist.psu.edu/mceliece03guruswamisudan.html
418  F evalhasse(const FXY &g, unsigned int r, unsigned int s,
419  F alpha, F beta, Ccache_t &Ccache);
420 
421  // Depth-first search on the tree of coefficients; used in
422  // Roth-Ruckenstein.
423  void dfs(vector<FX> &res,
424  int u,
425  vector<int> &pi,
426  vector<int> &Deg,
427  vector<F> &Coeff,
428  vector<FXY> &Q,
429  int &t,
430  int degreebound);
431 
432  // Return a list of roots for y of the bivariate polynomial
433  // P(x,y). If degreebound >= 0, only return those roots with
434  // degree <= degreebound. This routine only works over fields F
435  // (not rings).
436  vector<FX> rr_findroots(const FXY &P, int degreebound);
437 
438  // In the case of ZZ_p, store the factors of the modulus p1*p2.
439  // If it's a field, p1 should be 1 and p2 should be prime.
440  ZZ p1, p2;
441 };
442 
443 // The two types of RSDecoders I've tested. These are the types you
444 // would use to create a RSDecoder; i.e.:
445 //
446 // RSDecoder_ZZ_p decoder(p1, p2);
447 //
448 // or
449 //
450 // RSDecoder_GF2E decoder();
451 //
452 // Remember to also call ZZ_p::init(p1*p2) or GF2E::init(modpoly) as
453 // appropriate before creating the RSDecoder.
456 
457 // Comparison functions used to let polynomials be keys for maps
458 bool cmp (const GF2EX& a, const GF2EX& b);
459 bool cmp (const ZZ_pX& a, const ZZ_pX& b);
460 
461 #include "recover.h"
462 #include "rsdecoder_impl.h"
463 
464 #endif
vector< map< dbsize_t, F > > recovered
Recovered words by word index.
Definition: rsdecoder.h:97
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
vector< FX > phis
Reconstructed polynomials.
Definition: rsdecoder.h:81
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
vector< nservers_t > G
Server indices that agree.
Definition: rsdecoder.h:79
RecoveryPoly(vector< nservers_t > G, FX phi)
Constructor.
Definition: rsdecoder.h:61
FX phi
Reconstructed polynomial.
Definition: rsdecoder.h:66
DecoderResult(vector< nservers_t > G, vector< map< dbsize_t, F > > recovered)
Constructor.
Definition: rsdecoder.h:91
RSDecoder()
GF2E Constructor.
Definition: rsdecoder.h:166
Definition: FXY.h:53
static string append(const string &s, const F &wz, unsigned int bytes_per_word)
A helper function to append an element of F to a string.
RecoveryPolyMulti(vector< nservers_t > G, vector< FX > phis)
Constructor.
Definition: rsdecoder.h:76
vector< nservers_t > G
Server indices that agree.
Definition: rsdecoder.h:64
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
RSDecoder(const ZZ &p1, const ZZ &p2)
ZZ_p Constructor.
Definition: rsdecoder.h:171
vector< nservers_t > G
Server indices that agree.
Definition: rsdecoder.h:95