Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

polynomi.cpp

00001 // polynomi.cpp - written and placed in the public domain by Wei Dai
00002 
00003 // Part of the code for polynomial evaluation and interpolation
00004 // originally came from Hal Finney's public domain secsplit.c.
00005 
00006 #include "pch.h"
00007 #include "polynomi.h"
00008 
00009 #include <strstream>
00010 #include <iostream>
00011 
00012 NAMESPACE_BEGIN(CryptoPP)
00013 
00014 template <class T>
00015 void PolynomialOver<T>::Randomize(RandomNumberGenerator &rng, const RandomizationParameter &parameter, const Ring &ring)
00016 {
00017         m_coefficients.resize(parameter.m_coefficientCount);
00018         for (unsigned int i=0; i<m_coefficients.size(); ++i)
00019                 m_coefficients[i] = ring.RandomElement(rng, parameter.m_coefficientParameter);
00020 }
00021 
00022 template <class T>
00023 void PolynomialOver<T>::FromStr(const char *str, const Ring &ring)
00024 {
00025         std::istrstream in((char *)str);
00026         bool positive = true;
00027         CoefficientType coef;
00028         unsigned int power;
00029 
00030         while (in)
00031         {
00032                 std::ws(in);
00033                 if (in.peek() == 'x')
00034                         coef = ring.One();
00035                 else
00036                         in >> coef;
00037 
00038                 std::ws(in);
00039                 if (in.peek() == 'x')
00040                 {
00041                         in.get();
00042                         std::ws(in);
00043                         if (in.peek() == '^')
00044                         {
00045                                 in.get();
00046                                 in >> power;
00047                         }
00048                         else
00049                                 power = 1;
00050                 }
00051                 else
00052                         power = 0;
00053 
00054                 if (!positive)
00055                         coef = ring.Inverse(coef);
00056 
00057                 SetCoefficient(power, coef, ring);
00058 
00059                 std::ws(in);
00060                 switch (in.get())
00061                 {
00062                 case '+':
00063                         positive = true;
00064                         break;
00065                 case '-':
00066                         positive = false;
00067                         break;
00068                 default:
00069                         return;         // something's wrong with the input string
00070                 }
00071         }
00072 }
00073 
00074 template <class T>
00075 unsigned int PolynomialOver<T>::CoefficientCount(const Ring &ring) const
00076 {
00077         unsigned count = m_coefficients.size();
00078         while (count && ring.Equal(m_coefficients[count-1], ring.Zero()))
00079                 count--;
00080         const_cast<std::vector<CoefficientType> &>(m_coefficients).resize(count);
00081         return count;
00082 }
00083 
00084 template <class T>
00085 PolynomialOver<T>::CoefficientType PolynomialOver<T>::GetCoefficient(unsigned int i, const Ring &ring) const 
00086 {
00087         return (i < m_coefficients.size()) ? m_coefficients[i] : ring.Zero();
00088 }
00089 
00090 template <class T>
00091 PolynomialOver<T>&  PolynomialOver<T>::operator=(const PolynomialOver<T>& t)
00092 {
00093         if (this != &t)
00094         {
00095                 m_coefficients.resize(t.m_coefficients.size());
00096                 for (unsigned int i=0; i<m_coefficients.size(); i++)
00097                         m_coefficients[i] = t.m_coefficients[i];
00098         }
00099         return *this;
00100 }
00101 
00102 template <class T>
00103 PolynomialOver<T>& PolynomialOver<T>::Accumulate(const PolynomialOver<T>& t, const Ring &ring)
00104 {
00105         unsigned int count = t.CoefficientCount(ring);
00106 
00107         if (count > CoefficientCount(ring))
00108                 m_coefficients.resize(count, ring.Zero());
00109 
00110         for (unsigned int i=0; i<count; i++)
00111                 ring.Accumulate(m_coefficients[i], t.GetCoefficient(i, ring));
00112 
00113         return *this;
00114 }
00115 
00116 template <class T>
00117 PolynomialOver<T>& PolynomialOver<T>::Reduce(const PolynomialOver<T>& t, const Ring &ring)
00118 {
00119         unsigned int count = t.CoefficientCount(ring);
00120 
00121         if (count > CoefficientCount(ring))
00122                 m_coefficients.resize(count, ring.Zero());
00123 
00124         for (unsigned int i=0; i<count; i++)
00125                 ring.Reduce(m_coefficients[i], t.GetCoefficient(i, ring));
00126 
00127         return *this;
00128 }
00129 
00130 template <class T>
00131 PolynomialOver<T>::CoefficientType PolynomialOver<T>::EvaluateAt(const CoefficientType &x, const Ring &ring) const
00132 {
00133         int degree = Degree(ring);
00134 
00135         if (degree < 0)
00136                 return ring.Zero();
00137 
00138         CoefficientType result = m_coefficients[degree];
00139         for (int j=degree-1; j>=0; j--)
00140         {
00141                 result = ring.Multiply(result, x);
00142                 ring.Accumulate(result, m_coefficients[j]);
00143         }
00144         return result;
00145 }
00146 
00147 template <class T>
00148 PolynomialOver<T>& PolynomialOver<T>::ShiftLeft(unsigned int n, const Ring &ring)
00149 {
00150         unsigned int i = CoefficientCount(ring) + n;
00151         m_coefficients.resize(i, ring.Zero());
00152         while (i > n)
00153         {
00154                 i--;
00155                 m_coefficients[i] = m_coefficients[i-n];
00156         }
00157         while (i)
00158         {
00159                 i--;
00160                 m_coefficients[i] = ring.Zero();
00161         }
00162         return *this;
00163 }
00164 
00165 template <class T>
00166 PolynomialOver<T>& PolynomialOver<T>::ShiftRight(unsigned int n, const Ring &ring)
00167 {
00168         unsigned int count = CoefficientCount(ring);
00169         if (count > n)
00170         {
00171                 for (unsigned int i=0; i<count-n; i++)
00172                         m_coefficients[i] = m_coefficients[i+n];
00173                 m_coefficients.resize(count-n, ring.Zero());
00174         }
00175         else
00176                 m_coefficients.resize(0, ring.Zero());
00177         return *this;
00178 }
00179 
00180 template <class T>
00181 void PolynomialOver<T>::SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring)
00182 {
00183         if (i >= m_coefficients.size())
00184                 m_coefficients.resize(i+1, ring.Zero());
00185         m_coefficients[i] = value;
00186 }
00187 
00188 template <class T>
00189 void PolynomialOver<T>::Negate(const Ring &ring)
00190 {
00191         unsigned int count = CoefficientCount(ring);
00192         for (unsigned int i=0; i<count; i++)
00193                 m_coefficients[i] = ring.Inverse(m_coefficients[i]);
00194 }
00195 
00196 template <class T>
00197 void PolynomialOver<T>::swap(PolynomialOver<T> &t)
00198 {
00199         m_coefficients.swap(t.m_coefficients);
00200 }
00201 
00202 template <class T>
00203 bool PolynomialOver<T>::Equals(const PolynomialOver<T>& t, const Ring &ring) const
00204 {
00205         unsigned int count = CoefficientCount(ring);
00206 
00207         if (count != t.CoefficientCount(ring))
00208                 return false;
00209 
00210         for (unsigned int i=0; i<count; i++)
00211                 if (!ring.Equal(m_coefficients[i], t.m_coefficients[i]))
00212                         return false;
00213 
00214         return true;
00215 }
00216 
00217 template <class T>
00218 PolynomialOver<T> PolynomialOver<T>::Plus(const PolynomialOver<T>& t, const Ring &ring) const
00219 {
00220         unsigned int i;
00221         unsigned int count = CoefficientCount(ring);
00222         unsigned int tCount = t.CoefficientCount(ring);
00223 
00224         if (count > tCount)
00225         {
00226                 PolynomialOver<T> result(ring, count);
00227 
00228                 for (i=0; i<tCount; i++)
00229                         result.m_coefficients[i] = ring.Add(m_coefficients[i], t.m_coefficients[i]);
00230                 for (; i<count; i++)
00231                         result.m_coefficients[i] = m_coefficients[i];
00232 
00233                 return result;
00234         }
00235         else
00236         {
00237                 PolynomialOver<T> result(ring, tCount);
00238 
00239                 for (i=0; i<count; i++)
00240                         result.m_coefficients[i] = ring.Add(m_coefficients[i], t.m_coefficients[i]);
00241                 for (; i<tCount; i++)
00242                         result.m_coefficients[i] = t.m_coefficients[i];
00243 
00244                 return result;
00245         }
00246 }
00247 
00248 template <class T>
00249 PolynomialOver<T> PolynomialOver<T>::Minus(const PolynomialOver<T>& t, const Ring &ring) const
00250 {
00251         unsigned int i;
00252         unsigned int count = CoefficientCount(ring);
00253         unsigned int tCount = t.CoefficientCount(ring);
00254 
00255         if (count > tCount)
00256         {
00257                 PolynomialOver<T> result(ring, count);
00258 
00259                 for (i=0; i<tCount; i++)
00260                         result.m_coefficients[i] = ring.Subtract(m_coefficients[i], t.m_coefficients[i]);
00261                 for (; i<count; i++)
00262                         result.m_coefficients[i] = m_coefficients[i];
00263 
00264                 return result;
00265         }
00266         else
00267         {
00268                 PolynomialOver<T> result(ring, tCount);
00269 
00270                 for (i=0; i<count; i++)
00271                         result.m_coefficients[i] = ring.Subtract(m_coefficients[i], t.m_coefficients[i]);
00272                 for (; i<tCount; i++)
00273                         result.m_coefficients[i] = ring.Inverse(t.m_coefficients[i]);
00274 
00275                 return result;
00276         }
00277 }
00278 
00279 template <class T>
00280 PolynomialOver<T> PolynomialOver<T>::Inverse(const Ring &ring) const
00281 {
00282         unsigned int count = CoefficientCount(ring);
00283         PolynomialOver<T> result(ring, count);
00284 
00285         for (unsigned int i=0; i<count; i++)
00286                 result.m_coefficients[i] = ring.Inverse(m_coefficients[i]);
00287 
00288         return result;
00289 }
00290 
00291 template <class T>
00292 PolynomialOver<T> PolynomialOver<T>::Times(const PolynomialOver<T>& t, const Ring &ring) const
00293 {
00294         if (IsZero(ring) || t.IsZero(ring))
00295                 return PolynomialOver<T>();
00296 
00297         unsigned int count1 = CoefficientCount(ring), count2 = t.CoefficientCount(ring);
00298         PolynomialOver<T> result(ring, count1 + count2 - 1);
00299 
00300         for (unsigned int i=0; i<count1; i++)
00301                 for (unsigned int j=0; j<count2; j++)
00302                         ring.Accumulate(result.m_coefficients[i+j], ring.Multiply(m_coefficients[i], t.m_coefficients[j]));
00303 
00304         return result;
00305 }
00306 
00307 template <class T>
00308 PolynomialOver<T> PolynomialOver<T>::DividedBy(const PolynomialOver<T>& t, const Ring &ring) const
00309 {
00310         PolynomialOver<T> remainder, quotient;
00311         Divide(remainder, quotient, *this, t, ring);
00312         return quotient;
00313 }
00314 
00315 template <class T>
00316 PolynomialOver<T> PolynomialOver<T>::Modulo(const PolynomialOver<T>& t, const Ring &ring) const
00317 {
00318         PolynomialOver<T> remainder, quotient;
00319         Divide(remainder, quotient, *this, t, ring);
00320         return remainder;
00321 }
00322 
00323 template <class T>
00324 PolynomialOver<T> PolynomialOver<T>::MultiplicativeInverse(const Ring &ring) const
00325 {
00326         return Degree(ring)==0 ? ring.MultiplicativeInverse(m_coefficients[0]) : ring.Zero();
00327 }
00328 
00329 template <class T>
00330 bool PolynomialOver<T>::IsUnit(const Ring &ring) const
00331 {
00332         return Degree(ring)==0 && ring.IsUnit(m_coefficients[0]);
00333 }
00334 
00335 template <class T>
00336 std::istream& PolynomialOver<T>::Input(std::istream &in, const Ring &ring)
00337 {
00338         char c;
00339         unsigned int length = 0;
00340         SecBlock<char> str(length + 16);
00341         bool paren = false;
00342 
00343         std::ws(in);
00344 
00345         if (in.peek() == '(')
00346         {
00347                 paren = true;
00348                 in.get();
00349         }
00350 
00351         do
00352         {
00353                 in.read(&c, 1);
00354                 str[length++] = c;
00355                 if (length >= str.size)
00356                         str.Grow(length + 16);
00357         }
00358         // if we started with a left paren, then read until we find a right paren,
00359         // otherwise read until the end of the line
00360         while (in && ((paren && c != ')') || (!paren && c != '\n')));
00361 
00362         str[length-1] = '\0';
00363         *this = PolynomialOver<T>(str, ring);
00364 
00365         return in;
00366 }
00367 
00368 template <class T>
00369 std::ostream& PolynomialOver<T>::Output(std::ostream &out, const Ring &ring) const
00370 {
00371         unsigned int i = CoefficientCount(ring);
00372         if (i)
00373         {
00374                 bool firstTerm = true;
00375 
00376                 while (i--)
00377                 {
00378                         if (m_coefficients[i] != ring.Zero())
00379                         {
00380                                 if (firstTerm)
00381                                 {
00382                                         firstTerm = false;
00383                                         if (!i || !ring.Equal(m_coefficients[i], ring.One()))
00384                                                 out << m_coefficients[i];
00385                                 }
00386                                 else
00387                                 {
00388                                         CoefficientType inverse = ring.Inverse(m_coefficients[i]);
00389                                         ostrstream pstr, nstr;
00390 
00391                                         pstr << m_coefficients[i];
00392                                         nstr << inverse;
00393 
00394                                         if (pstr.pcount() <= nstr.pcount())
00395                                         {
00396                                                 out << " + "; 
00397                                                 if (!i || !ring.Equal(m_coefficients[i], ring.One()))
00398                                                         out << m_coefficients[i];
00399                                         }
00400                                         else
00401                                         {
00402                                                 out << " - "; 
00403                                                 if (!i || !ring.Equal(inverse, ring.One()))
00404                                                         out << inverse;
00405                                         }
00406                                 }
00407 
00408                                 switch (i)
00409                                 {
00410                                 case 0:
00411                                         break;
00412                                 case 1:
00413                                         out << "x";
00414                                         break;
00415                                 default:
00416                                         out << "x^" << i;
00417                                 }
00418                         }
00419                 }
00420         }
00421         else
00422         {
00423                 out << ring.Zero();
00424         }
00425         return out;
00426 }
00427 
00428 template <class T>
00429 void PolynomialOver<T>::Divide(PolynomialOver<T> &r, PolynomialOver<T> &q, const PolynomialOver<T> &a, const PolynomialOver<T> &d, const Ring &ring)
00430 {
00431         unsigned int i = a.CoefficientCount(ring);
00432         const int dDegree = d.Degree(ring);
00433 
00434         if (dDegree < 0)
00435                 throw DivideByZero();
00436 
00437         r = a;
00438         q.m_coefficients.resize(STDMAX(0, int(i - dDegree)));
00439 
00440         while (i > (unsigned int)dDegree)
00441         {
00442                 --i;
00443                 q.m_coefficients[i-dDegree] = ring.Divide(r.m_coefficients[i], d.m_coefficients[dDegree]);
00444                 for (int j=0; j<=dDegree; j++)
00445                         ring.Reduce(r.m_coefficients[i-dDegree+j], ring.Multiply(q.m_coefficients[i-dDegree], d.m_coefficients[j]));
00446         }
00447 
00448         r.CoefficientCount(ring);       // resize r.m_coefficients
00449 }
00450 
00451 // ********************************************************
00452 
00453 // helper function for Interpolate() and InterpolateAt()
00454 template <class T>
00455 void RingOfPolynomialsOver<T>::CalculateAlpha(std::vector<CoefficientType> &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const
00456 {
00457         for (unsigned int j=0; j<n; ++j)
00458                 alpha[j] = y[j];
00459 
00460         for (unsigned int k=1; k<n; ++k)
00461         {
00462                 for (unsigned int j=n-1; j>=k; --j)
00463                 {
00464                         m_ring.Reduce(alpha[j], alpha[j-1]);
00465 
00466                         CoefficientType d = m_ring.Subtract(x[j], x[j-k]);
00467                         if (!m_ring.IsUnit(d))
00468                                 throw InterpolationFailed();
00469                         alpha[j] = m_ring.Divide(alpha[j], d);
00470                 }
00471         }
00472 }
00473 
00474 template <class T>
00475 RingOfPolynomialsOver<T>::Element RingOfPolynomialsOver<T>::Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const
00476 {
00477         assert(n > 0);
00478 
00479         std::vector<CoefficientType> alpha(n);
00480         CalculateAlpha(alpha, x, y, n);
00481 
00482         std::vector<CoefficientType> coefficients((size_t)n, m_ring.Zero());
00483         coefficients[0] = alpha[n-1];
00484 
00485         for (int j=n-2; j>=0; --j)
00486         {
00487                 for (unsigned int i=n-j-1; i>0; i--)
00488                         coefficients[i] = m_ring.Subtract(coefficients[i-1], m_ring.Multiply(coefficients[i], x[j]));
00489 
00490                 coefficients[0] = m_ring.Subtract(alpha[j], m_ring.Multiply(coefficients[0], x[j]));
00491         }
00492 
00493         return PolynomialOver<T>(coefficients.begin(), coefficients.end());
00494 }
00495 
00496 template <class T>
00497 RingOfPolynomialsOver<T>::CoefficientType RingOfPolynomialsOver<T>::InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const
00498 {
00499         assert(n > 0);
00500 
00501         std::vector<CoefficientType> alpha(n);
00502         CalculateAlpha(alpha, x, y, n);
00503 
00504         CoefficientType result = alpha[n-1];
00505         for (int j=n-2; j>=0; --j)
00506         {
00507                 result = m_ring.Multiply(result, m_ring.Subtract(position, x[j]));
00508                 m_ring.Accumulate(result, alpha[j]);
00509         }
00510         return result;
00511 }
00512 
00513 template <class Ring, class Element>
00514 void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n)
00515 {
00516         for (unsigned int i=0; i<n; i++)
00517         {
00518                 Element t = ring.One();
00519                 for (unsigned int j=0; j<n; j++)
00520                         if (i != j)
00521                                 t = ring.Multiply(t, ring.Subtract(x[i], x[j]));
00522                 w[i] = ring.MultiplicativeInverse(t);
00523         }
00524 }
00525 
00526 template <class Ring, class Element>
00527 void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n)
00528 {
00529         assert(n > 0);
00530 
00531         std::vector<Element> a(2*n-1);
00532         unsigned int i;
00533 
00534         for (i=0; i<n; i++)
00535                 a[n-1+i] = ring.Subtract(position, x[i]);
00536 
00537         for (i=n-1; i>1; i--)
00538                 a[i-1] = ring.Multiply(a[2*i], a[2*i-1]);
00539 
00540         a[0] = ring.One();
00541 
00542         for (i=0; i<n-1; i++)
00543         {
00544                 std::swap(a[2*i+1], a[2*i+2]);
00545                 a[2*i+1] = ring.Multiply(a[i], a[2*i+1]);
00546                 a[2*i+2] = ring.Multiply(a[i], a[2*i+2]);
00547         }
00548 
00549         for (i=0; i<n; i++)
00550                 v[i] = ring.Multiply(a[n-1+i], w[i]);
00551 }
00552 
00553 template <class Ring, class Element>
00554 Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n)
00555 {
00556         Element result = ring.Zero();
00557         for (unsigned int i=0; i<n; i++)
00558                 ring.Accumulate(result, ring.Multiply(y[i], v[i]));
00559         return result;
00560 }
00561 
00562 // ********************************************************
00563 
00564 template <class T, int instance>
00565 const PolynomialOverFixedRing<T, instance> &PolynomialOverFixedRing<T, instance>::Zero()
00566 {
00567         static const PolynomialOverFixedRing<T, instance> zero;
00568         return zero;
00569 }
00570 
00571 template <class T, int instance>
00572 const PolynomialOverFixedRing<T, instance> &PolynomialOverFixedRing<T, instance>::One()
00573 {
00574         static const PolynomialOverFixedRing<T, instance> one = fixedRing.One();
00575         return one;
00576 }
00577 
00578 NAMESPACE_END

Generated at Mon Jan 15 01:16:35 2001 for Crypto++ by doxygen1.2.4 written by Dimitri van Heesch, © 1997-2000