Main Page   Reference Manual   Compound List   File List  

libecc/polynomial.h

Go to the documentation of this file.
00001 //
00008 //
00009 // This file is part of the libecc package.
00010 // Copyright (C) 2002, by
00011 //
00012 // Carlo Wood, Run on IRC <carlo@alinoe.com>
00013 // RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
00014 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
00015 //
00016 // This program is free software; you can redistribute it and/or
00017 // modify it under the terms of the GNU General Public License
00018 // as published by the Free Software Foundation; either version 2
00019 // of the License, or (at your option) any later version.
00020 // 
00021 // This program is distributed in the hope that it will be useful,
00022 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024 // GNU General Public License for more details.
00025 // 
00026 // You should have received a copy of the GNU General Public License
00027 // along with this program; if not, write to the Free Software
00028 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00029 //
00030 
00031 #ifndef LIBECC_POLYNOMIAL_H
00032 #define LIBECC_POLYNOMIAL_H
00033 
00034 #include <libecc/bitset.h>
00035 #if ECC_DEBUGOUTPUT
00036 #include <libcw/cwprint.h>
00037 #endif
00038 
00039 namespace libecc {
00040 
00277 template<unsigned int m, unsigned int k>
00278   class polynomial {
00279     public:
00280       // Fix this if you add members in front of M_coefficients.
00281       static size_t const offsetof_vector = bitset<m>::offsetof_vector;
00282 
00283     private:
00284       bitset<m> M_coefficients;
00285       static polynomial<m, k> const one;
00286 
00287     public:
00291       static polynomial const& unity(void) { return one; }
00292 
00293     public:
00297       polynomial(void) { }
00298 
00302       explicit polynomial(bitset_digit_t coefficients) : M_coefficients(coefficients) { }
00303 
00307       polynomial(polynomial const& p) : M_coefficients(p.M_coefficients) { }
00308 
00312       explicit polynomial(bitset<m> const& coefficients) : M_coefficients(coefficients) { }
00313 
00317       polynomial(std::string const& coefficients) : M_coefficients(coefficients) { }
00318 
00332       polynomial(Operator::bitsetExpression<m, false, false, Operator::bitsetXOR> const& expression) : M_coefficients(expression) { }
00333 
00337       polynomial& operator=(polynomial const& p) { M_coefficients = p.M_coefficients; return *this; }
00338 
00342       polynomial& operator=(bitset<m> const& coefficients) { M_coefficients = coefficients; return *this; }
00343 
00348       polynomial& operator=(Operator::bitsetExpression<m, false, false, Operator::bitsetXOR> const& expression);
00349 
00353       polynomial(polynomial const& b, polynomial const& c);
00354 
00358       static unsigned int const square_digits = 2 * bitset_base<m>::digits + 4;
00359 
00375       polynomial& square(bitset_digit_t* tmpbuf) const; // tmpbuf must be an array of `square_digits' bitset_digit_t.
00376 
00380       bool sqrt(void);
00381 
00382       // The field arithmetic is implemented in terms of operations on the bits.
00386       polynomial& operator+=(polynomial const& p) { M_coefficients ^= p.M_coefficients; return *this; }
00387 
00391       polynomial& operator-=(polynomial const& p) { M_coefficients ^= p.M_coefficients; return *this; }
00392 
00396       polynomial& operator*=(polynomial const& p);
00397 
00401       polynomial& operator/=(polynomial const& p);
00402 
00409       friend Operator::bitsetExpression<m, false, false, Operator::bitsetXOR> operator+ <>(polynomial const& p1, polynomial const& p2);
00410 
00417       friend Operator::bitsetExpression<m, false, false, Operator::bitsetXOR> operator- <>(polynomial const& p1, polynomial const& p2);
00418 
00422       friend polynomial operator* <>(polynomial const& p1, polynomial const& p2);
00423 
00427       friend polynomial operator/ <>(polynomial const& p1, polynomial const& p2);
00428 
00432       friend bool operator== <>(polynomial const& p1, polynomial const& p2);
00433 
00437       friend bool operator!= <>(polynomial const& p1, polynomial const& p2);
00438 
00444       friend std::ostream& operator<< <>(std::ostream& os, polynomial const& p);
00445 
00449       bitset<m> const& get_bitset(void) const { return M_coefficients; }
00450 
00454       bitset<m>& get_bitset(void) { return M_coefficients; }
00455 
00456     private:
00457       static void reduce(bitset_digit_t* buf);
00458       static bitset_digit_t reducea(bitset_digit_t const* a, bitset_digit_t* b, bitset_digit_t* c);
00459 
00460       void multiply_with(polynomial const& p1, bitset<m>& result) const;
00461   };
00462 
00463 template<unsigned int m, unsigned int k>
00464   polynomial<m, k> const polynomial<m, k>::one(1);
00465 
00466 template<unsigned int m, unsigned int k>
00467   bool polynomial<m, k>::sqrt(void)
00468   {
00469     bitset<m> highbits;
00470     highbits.reset();
00471 
00472     // First convert all odd powers into even powers
00473     if ((m & 1) == 1)
00474     {
00475       if ((k & 1) == 1)         // m and k are odd?
00476       {
00477         for(unsigned int bit = 1; bit < m; bit += 2)
00478         {
00479           if (M_coefficients.test(bit))
00480           {
00481             if (bit >= m - k)
00482               highbits.flip(bit + k - m);
00483             else
00484               M_coefficients.flip(bit + k);
00485             highbits.flip(bit);
00486           }
00487         }
00488       }
00489       else                      // m is odd and k is even
00490       {
00491         for(unsigned int bit = 1; bit < m; bit += 2)
00492         {
00493           if (M_coefficients.test(bit))
00494           {
00495             if (bit >= m - k)
00496             {
00497               M_coefficients.flip(bit + 2 * k - m);
00498               M_coefficients.flip(bit + k - m);
00499             }
00500             else
00501               M_coefficients.flip(bit + k);
00502             highbits.flip(bit);
00503           }
00504         }
00505       }
00506     }
00507     else if ((k & 1) == 1)      // m is even and k is odd
00508     {
00509       for(unsigned int bit = 1; bit < m; bit += 2)
00510       {
00511         if (M_coefficients.test(bit))
00512         {
00513           if (bit < k)
00514           {
00515             M_coefficients.flip(bit + k);
00516             M_coefficients.flip(bit + m - k);
00517             highbits.flip(bit + m - k);
00518           }
00519           else
00520           {
00521             M_coefficients.flip(bit - k);
00522             highbits.flip(bit - k);
00523           }
00524         }
00525       }
00526     }
00527     else                        // m and k are both even (actually, this should never be used as reduction polynomial).
00528     {
00529       for(unsigned int bit = 1; bit < m; bit += 2)
00530         if (M_coefficients.test(bit))
00531           return false;         // This can't be a square
00532     }
00533 
00534     // Next handle the remaining even powers
00535     unsigned int bit_to = 1;
00536     for(unsigned int bit = 2; bit < m; bit += 2)
00537     {
00538       if (M_coefficients.test(bit))
00539         M_coefficients.set(bit_to);
00540       else
00541         M_coefficients.clear(bit_to);
00542       ++bit_to;
00543     }
00544     for(unsigned int bit = m % 2; bit < m; bit += 2)
00545     {
00546       if (highbits.test(bit))
00547         M_coefficients.set(bit_to);
00548       else
00549         M_coefficients.clear(bit_to);
00550       ++bit_to;
00551     }
00552     return true;
00553   }
00554 
00555 template<unsigned int m, unsigned int k>
00556   polynomial<m, k>&
00557   polynomial<m, k>::operator*=(polynomial const& e1)
00558   {
00559     multiply_with(e1, M_coefficients);
00560     return *this;
00561   }
00562 
00563 template<unsigned int m, unsigned int k>
00564   inline polynomial<m, k>&
00565   polynomial<m, k>::operator=(Operator::bitsetExpression<m, false, false, Operator::bitsetXOR> const& expression)
00566   {
00567     M_coefficients = expression;
00568     return *this;
00569   }
00570 
00571 template<unsigned int m, unsigned int k>
00572   void
00573   polynomial<m, k>::multiply_with(polynomial const& p1, bitset<m>& result) const
00574   {
00575     bitset_digit_t output[bitset<m>::digits * 2] __attribute__ ((aligned (8)));
00576 
00577     // Find the first non-zero digit in the input polynomial of this object.
00578     unsigned int digit = 0;
00579     while(M_coefficients.digit(digit) == 0)             // Still zero?
00580     {
00581       output[digit] = 0;                                // That means that the output will end on zero too.
00582       if (++digit == bitset<m>::digits)
00583       {
00584         result.reset();                                 // The whole polynomial is zero, the result will be zero too.
00585         return;
00586       }
00587     }
00588     unsigned int uninitialized_digit = digit;           // The next digit of `output' that has not yet been initialized.
00589     // Find the first digit in the input polynomial of this object whose first bit is set.
00590     for(; digit < bitset<m>::digits; ++digit)
00591     {
00592       if ((M_coefficients.digit(digit) & 1))            // Is the first bit set?
00593       {
00594         // Set the output to p1 times this bit.
00595         for (unsigned int d = 0; d < bitset<m>::digits; ++d)
00596           output[d + digit] = p1.get_bitset().digit(d);
00597         uninitialized_digit = bitset<m>::digits + digit;
00598         ++digit;                                        // Set to the next input digit.
00599         break;
00600       }
00601       output[digit] = 0;                                // Initialize this digit of the output to 0.
00602       ++uninitialized_digit;
00603     }
00604     // Set the remaining digits to zero, if any.
00605     for(unsigned int remaining_digit = uninitialized_digit; remaining_digit < sizeof(output) / sizeof(bitset_digit_t); ++remaining_digit)
00606       output[remaining_digit] = 0;
00607     // Find for the remaining input digits the ones that have their first bit set.
00608     for(; digit < bitset<m>::digits; ++digit)
00609       if ((M_coefficients.digit(digit) & 1))            // Is the first bit set?
00610       {
00611         // Add p1 times this bit to the output.
00612         for (unsigned int d = 0; d < bitset<m>::digits; ++d)
00613           output[d + digit] ^= p1.get_bitset().digit(d);
00614       }
00615     // Create a bitset that will contain p1, shifted at most bitset_digit_bits - 1 to the left.
00616     bitset<m + bitset_digit_bits - 1> shifted_p1;
00617     // Start with having it shifted 1 bit to the left.
00618     bitset_digit_t carry = 0;
00619     unsigned int d = 0;
00620     for(bitset_digit_t const* ptr = p1.get_bitset().digits_ptr(); ptr < p1.get_bitset().digits_ptr() + bitset<m>::digits; ++ptr, ++d)
00621     {
00622       shifted_p1.rawdigit(d) = (*ptr << 1) | carry;
00623       carry = *ptr >> (8 * sizeof(bitset_digit_t) - 1);
00624     }
00625     if (d < bitset<m + bitset_digit_bits - 1>::digits)
00626       shifted_p1.rawdigit(d) = carry;
00627     for(bitset_digit_t bitmask = 2;;)
00628     {
00629       for(unsigned int digit = 0; digit < bitset<m>::digits; ++digit)
00630         if ((M_coefficients.digit(digit) & bitmask))
00631         {
00632           for (unsigned int d = 0; d < shifted_p1.digits; ++d)
00633             output[d + digit] ^= shifted_p1.digit(d);
00634         }
00635       bitmask <<= 1;            // Next bit.
00636       if (bitmask == 0)         // Done?
00637         break;
00638       // Shift p1 one bit further to the left.
00639       shifted_p1.template shift_op<1, left, assign>(shifted_p1);
00640     }
00641     // Reduce the resulting output of the multiplication.
00642     reduce(output);
00643     // Copy the reduced output to `result'.
00644     std::memcpy(result.digits_ptr(), output, bitset<m>::digits * sizeof(bitset_digit_t));
00645   }
00646 
00647 #if ECC_DEBUG
00648 template<unsigned int m>
00649 struct div_tct {
00650   bitset_digit_t const* M_p;
00651   int M_deg;
00652   int M_low;
00653   div_tct(bitset<m> const& b, int deg, int low) : M_p(b.digits_ptr()), M_deg(deg), M_low(low) { }
00654   void print_on(std::ostream& os) const
00655   {
00656     int lowbit = (M_low >> bitset_digit_bits_log2) * bitset_digit_bits;
00657     if (lowbit > 0)
00658       lowbit = 0;
00659     for (int b = 2 * m - 1; b >= lowbit; --b)
00660     {
00661       if (b == M_deg)
00662         os << "\e[31m";
00663       int digitoffset = (b >> bitset_digit_bits_log2);
00664       bitset_digit_t mask = 1 << (b & (bitset_digit_bits - 1));
00665       if (M_p[digitoffset] & mask)
00666         os << '1';
00667       else
00668         os << '0';
00669       if (b == M_low)
00670         os << "\e[0m";
00671       if (b == 0)
00672         os << '.';
00673     }
00674   }
00675 };
00676 #endif
00677 
00678 template<unsigned int m, unsigned int k>
00679   polynomial<m, k>&
00680   polynomial<m, k>::operator/=(polynomial const& e1)
00681   {
00682 #if ECC_DEBUG
00683     Dout(dc::polynomial|noprefix_cf, "");
00684     Dout(dc::polynomial, "Entering polynomial<" << m << ", " << k << ">::operator/=()");
00685     polynomial<m, k> x(e1.get_bitset());
00686     polynomial<m, k> y(M_coefficients);
00687     Dout(dc::polynomial, "x(t) = " << x);
00688     Dout(dc::polynomial|flush_cf, "y(t) = " << y);
00689 #endif
00690 
00691     // The following algorithm is based on the algorithm
00692     // described in http://research.sun.com/techrep/2001/smli_tr-2001-95.ps
00693     // with significant optimization changes by Carlo Wood.
00694 
00695     // Make sure that there is enough space for a full bitset object
00696     // and align the bitsets on a multiple of bitset_digit_t.
00697     static unsigned int const digit_offset_UV = ((sizeof(bitset<m>) * 8 - 1) / bitset_digit_bits + 1);
00698     static unsigned int const offset_UV = digit_offset_UV * bitset_digit_bits;
00699     // Make room for exponents from at least t^-m till t^2m.
00700     static unsigned int const digit_size_UV = 3 * digit_offset_UV;
00701     // Variables A and B do not need this much space.
00702     static unsigned int const digit_size_AB = bitset<m>::digits;
00703     // One digit of padding, needed for assembly routine.
00704     static unsigned int const padding_digit_size = 1;
00705 
00706     // Declare stack space for four variables.
00707     bitset_digit_t bitpool [5 * padding_digit_size + 2 * digit_size_AB + 2 * digit_size_UV]
00708         __attribute__ ((__aligned__ (32)));
00709     std::memset((char*)bitpool, 0, sizeof(bitpool));
00710 
00711     bitset<m>& A(*(bitset<m>*)&bitpool[padding_digit_size]);
00712     bitset<m>& B(*(bitset<m>*)&bitpool[2 * padding_digit_size + digit_size_AB]);
00713     bitset<m>& U(*(bitset<m>*)&bitpool[3 * padding_digit_size + 2 * digit_size_AB + digit_offset_UV]);
00714     bitset<m>& V(*(bitset<m>*)&bitpool[4 * padding_digit_size + 2 * digit_size_AB + digit_size_UV + digit_offset_UV]);
00715 
00716     // The representation of U and V will be done with bitsets of size `digit_size_UV * bitset_digit_bits'.
00717     // This means that they contain powers of t with a negative exponent.
00718     // That is not a problem as those are well defined: t^(-n) = 1 / t^n.
00719 
00720     // Let M(t) = t^m + t^k + 1.
00721 #if ECC_DEBUG
00722     polynomial<m + 1, 1> M("1");
00723     M.get_bitset().set(k);
00724     M.get_bitset().set(m);
00725 #endif
00726 
00727     // Let U(t) = y(t) (= M_coefficients).
00728     Dout(dc::polynomial|flush_cf, "U <- y");
00729     U = M_coefficients;
00730 
00731     // Guess the maximum and minimum powers to be the possible limits.
00732     int degU = m - 1;
00733     int lowU = 0;
00734 
00735     // Let A(t) = x(t).
00736     Dout(dc::polynomial|flush_cf, "A <- x");
00737     A = e1.get_bitset();
00738 
00739     // Then
00740     //
00741     // A(t) * y(t) = U(t) * x(t)  [mod M(t)].
00742 
00743     // Let V(t) = 0
00744     // Let B = M(t)
00745     //
00746     // Then
00747     //
00748     // B(t) * y(t) = V(t) * x(t)  [mod M(t)].
00749     //
00750     // Let degA be the highest power of t in A.
00751     typename bitset<m>::const_reverse_iterator degA = A.rbegin();
00752     degA.find1();
00753     Dout(dc::polynomial|flush_cf, "deg(A) == " << degA);
00754 
00755     // Let lowA be the lowest power of t in A.
00756     typename bitset<m>::const_iterator lowA = A.begin();
00757     lowA.find1();
00758     Dout(dc::polynomial|flush_cf, "low(A) == " << lowA);
00759 
00760     unsigned int sizeA = static_cast<unsigned int>(degA) - static_cast<unsigned int>(lowA);
00761 
00762     // Let n = m - deg(A).
00763     unsigned int n = m - static_cast<unsigned int>(degA);
00764     //
00765     // Then B'(t) = B(t) - A(t) * t^n will have a degree less than m.
00766     // And
00767     //
00768     // B'(t) * y(t) = B(t) * y(t) - A(t) * y(t) * t^n =
00769     //              = V(t) * x(t) - U(t) * x(t) * t^n =
00770     //              = (V(t) - U(t) * t^n) * x(t) =
00771     //              = V'(t) * x(t)                      [mod M(t)].
00772     //
00773     // B <- B'
00774     Dout(dc::polynomial|flush_cf, "B <- A * t^" << n << " + " << M);
00775     B.xor_with_zero_padded(A, lowA, static_cast<unsigned int>(degA), n);
00776     B.template flip<m>();
00777     B.template flip<k>();
00778     B.template flip<0>();
00779 
00780     // Let degB be the highest power of t in B.
00781     typename bitset<m>::const_reverse_iterator degB = B.rbegin();
00782     degB.find1();
00783     Dout(dc::polynomial|flush_cf, "deg(B) == " << degB);
00784 
00785     // Let lowB be the lowest power of t in B.
00786     typename bitset<m>::const_iterator lowB = B.begin();
00787     lowB.find1();
00788     Dout(dc::polynomial|flush_cf, "low(B) == " << lowB);
00789 
00790     // V <- V'
00791     Dout(dc::polynomial|flush_cf, "V <- U * t^" << n << "  [mod " << M << "]");
00792     V.xor_with_zero_padded(U, 0, m - 1, n);
00793 
00794     int degV = degU + n;
00795     int lowV = lowU + n;
00796     
00797     unsigned int sizeB = static_cast<unsigned int>(degB) - static_cast<unsigned int>(lowB);
00798 
00799     if (sizeA > 0 && sizeB > 0)
00800       for(;;)
00801       {
00802         Dout(dc::polynomial|flush_cf, "A = " << cwprint(div_tct<m>(A, degA, lowA)));
00803         Dout(dc::polynomial|flush_cf, "B = " << cwprint(div_tct<m>(B, degB, lowB)));
00804         Dout(dc::polynomial|flush_cf, "U = " << cwprint(div_tct<m>(U, degU, lowU)));
00805         Dout(dc::polynomial|flush_cf, "V = " << cwprint(div_tct<m>(V, degV, lowV)));
00806         if (sizeA < sizeB)
00807         {
00808           int left_shift = static_cast<unsigned int>(lowB) - static_cast<unsigned int>(lowA);
00809           Dout(dc::polynomial|flush_cf, "B <- B + A * t^" << left_shift);
00810           B.xor_with_zero_padded(A, lowA, degA, left_shift);
00811           degB.find1();
00812           lowB.find1();
00813           sizeB = static_cast<unsigned int>(degB) - static_cast<unsigned int>(lowB);
00814           Dout(dc::polynomial|flush_cf, "V <- V + U * t^" << left_shift);
00815           V.xor_with_zero_padded(U, lowU, degU, left_shift);
00816           degV = std::max(degV, degU + left_shift);
00817           lowV = std::min(lowV, lowU + left_shift);
00818           if (sizeB == 0)
00819             break;
00820         }
00821         else
00822         {
00823           int left_shift = static_cast<unsigned int>(lowA) - static_cast<unsigned int>(lowB);
00824           Dout(dc::polynomial|flush_cf, "A <- A + B * t^" << left_shift);
00825           A.xor_with_zero_padded(B, lowB, degB, left_shift);
00826           degA.find1();
00827           lowA.find1();
00828           sizeA = static_cast<unsigned int>(degA) - static_cast<unsigned int>(lowA);
00829           Dout(dc::polynomial|flush_cf, "U <- U + V * t^" << left_shift);
00830           U.xor_with_zero_padded(V, lowV, degV, left_shift);
00831           degU = std::max(degU, degV + left_shift);
00832           lowU = std::min(lowU, lowV + left_shift);
00833           if (sizeA == 0)
00834             break;
00835         }
00836       }
00837 
00838     Dout(dc::polynomial|flush_cf, "A = " << cwprint(div_tct<m>(A, degA, lowA)));
00839     Dout(dc::polynomial|flush_cf, "B = " << cwprint(div_tct<m>(B, degB, lowB)));
00840     Dout(dc::polynomial|flush_cf, "U = " << cwprint(div_tct<m>(U, degU, lowU)));
00841     Dout(dc::polynomial|flush_cf, "V = " << cwprint(div_tct<m>(V, degV, lowV)));
00842 
00843     bitset<m>* R;
00844     // 'F' (Floating-point polynomial) will be shifted to the right and
00845     // is therefore defined to run from t^-2m till t^2m.  This means it will
00846     // be shifted OVER the other bitsets, but we don't need those anymore anyway.
00847     static unsigned int const offset_F = 2 * offset_UV;
00848     static unsigned int const size_F = 2 * m + offset_F;
00849     bitset<size_F>* F;
00850     int low1, lowR;
00851 #if ECC_DEBUG
00852     int degR;
00853 #endif
00854     if (sizeA == 0)
00855     {
00856       Dout(dc::polynomial|flush_cf, "R = U");
00857       R = &U;
00858       F = (bitset<size_F>*)&bitpool[3 * padding_digit_size + 2 * digit_size_AB - digit_offset_UV];
00859       low1 = lowA;
00860       lowR = lowU;
00861 #if ECC_DEBUG
00862       degR = degU;
00863 #endif
00864     }
00865     else if (sizeB == 0)
00866     {
00867       Dout(dc::polynomial|flush_cf, "R = V");
00868       R = &V;
00869       F = (bitset<size_F>*)&bitpool[4 * padding_digit_size + 2 * digit_size_AB + digit_size_UV - digit_offset_UV];
00870       low1 = lowB;
00871       lowR = lowV;
00872 #if ECC_DEBUG
00873       degR = degV;
00874 #endif
00875     }
00876 
00877     *F >>= low1;
00878     lowR -= low1;
00879 #if ECC_DEBUG
00880     degR -= low1;
00881 #endif
00882     // Get rid of negative exponents.
00883     Dout(dc::polynomial|flush_cf, "lowR = " << lowR);
00884     Dout(dc::polynomial|flush_cf, "R = " << cwprint(div_tct<m>(*R, degR, lowR)));
00885     if (k >= 32)
00886     {
00887       static int const digit_shift_k = k >> bitset_digit_bits_log2;
00888       static int const bit_shift_k = k & (bitset_digit_bits  - 1);
00889       static int const digit_shift_m = m >> bitset_digit_bits_log2;
00890       static int const bit_shift_m = m & (bitset_digit_bits  - 1);
00891       int first_digit = (lowR + offset_F) >> bitset_digit_bits_log2;
00892       bitset_digit_t* ptr = F->digits_ptr() + first_digit;
00893       bitset_digit_t* ptr1 = R->digits_ptr();
00894       while(ptr < ptr1)
00895       {
00896         ptr[digit_shift_k] ^= (*ptr) << bit_shift_k;
00897         if (bit_shift_k != 0)
00898           ptr[digit_shift_k + 1] ^= (*ptr) >> (32 - bit_shift_k);
00899         ptr[digit_shift_m] ^= (*ptr) << bit_shift_m;
00900         if (bit_shift_m != 0)
00901           ptr[digit_shift_m + 1] ^= (*ptr) >> (32 - bit_shift_m);
00902         ++ptr;
00903       }
00904     }
00905     else
00906     {
00907       for (int i = lowR + offset_F; i < offset_F; ++i)
00908       {
00909         if (F->test(i))
00910         {
00911 #if ECC_DEBUG
00912           F->flip(i);           // This is not really needed, but prints nicer output below.
00913 #endif
00914           F->flip(i + k);
00915           F->flip(i + m);
00916         }
00917       }
00918     }
00919 #if ECC_DEBUG
00920     lowR = 0;
00921     degR = 2 * m - 1;
00922 #endif
00923     Dout(dc::polynomial|flush_cf, "R = " << cwprint(div_tct<m>(*R, degR, lowR)));
00924     reduce(R->digits_ptr());
00925 #if ECC_DEBUG
00926     degR = m - 1;
00927 #endif
00928     Dout(dc::polynomial|flush_cf, "R = " << cwprint(div_tct<m>(*R, degR, lowR)));
00929     M_coefficients = *R;
00930 
00931     return *this;
00932   }
00933 
00934 // Solve x^2 + b x = c.
00935 // We assume that b != 0 and c != 0 and that there are 2 solutions.
00936 // The solutions are x1 and x1 + b.  This means that during the
00937 // 'wiping' of the matrix in order to solve x, one bit of x will
00938 // stay undetermined.  We need to take special care to make sure
00939 // that this will be a bit for which a bit of 'b' is set, otherwise
00940 // we'd return a wrong value.
00941 template<unsigned int m, unsigned int k>
00942   polynomial<m, k>::polynomial(polynomial<m, k> const& b, polynomial<m, k> const& c) : M_coefficients(c.M_coefficients)
00943   {
00944     using namespace libecc;
00945 
00946     bitset<m> reverse_b;
00947     reverse_b.reset();
00948     int bits_in_b = 0;
00949     short b_row;
00950     for (short i = m - 1; i >= 0; --i)
00951       if (b.M_coefficients.test(i))
00952       {
00953         reverse_b.set(m - 1 - i);
00954         ++bits_in_b;
00955         b_row = i;
00956       }
00957     if (bits_in_b == 0)
00958     {
00959       sqrt();
00960       return;
00961     }
00962     else if (bits_in_b != 1)
00963       b_row = -1;
00964     
00965     bitset<m> matrix[m];
00966     reverse_b.template shift_op<k + 1, libecc::left, libecc::assign>(matrix[k]);
00967     reverse_b.template shift_op<m - (k + 1), libecc::right, libecc::exor>(matrix[k]);   // reverse_b rotated right k + 1
00968     reverse_b.template shift_op<1, libecc::left, libecc::exor>(matrix[k]);
00969     reverse_b.template shift_op<m - (k - 1), libecc::left, libecc::exor>(matrix[k]);
00970     unsigned short i = k;
00971     for (unsigned short j = i + 1; j != k; j = (j + 1) % m)
00972     {
00973       matrix[i].template shift_op<1, libecc::left, libecc::assign>(matrix[j]);
00974       if (b.M_coefficients.test(j))
00975         matrix[j].template set<0>();
00976       i = j;
00977     }
00978 
00979 #if ECC_DEBUGOUTPUT
00980     LibEccDout(dc::polynomial, "b Matrix =");
00981     for (short row2 = m - 1; row2 >= 0; --row2)
00982       LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[row2]),
00983           &bitset<m>::base2_print_on) << "  x" << row2 << "   " << M_coefficients.test(row2) ? '1' : '0');
00984 #endif
00985 
00986     for (unsigned int col = 0; col < m; ++col)
00987     {
00988       unsigned int r = 2 * col;
00989       while(r >= m)
00990       {
00991         matrix[r - m].flip(col);
00992         r -= m - k;
00993       }
00994       matrix[r].flip(col);
00995     }
00996 
00997 #if ECC_DEBUGOUTPUT
00998     LibEccDout(dc::polynomial, "Matrix =");
00999     for (short row2 = m - 1; row2 >= 0; --row2)
01000       LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[row2]),
01001           &bitset<m>::base2_print_on) << "  x" << row2 << "   " << M_coefficients.test(row2) ? '1' : '0');
01002 #endif
01003 
01004     unsigned short rows[m];
01005     for (unsigned short i = 0; i < m; ++i)
01006       rows[i] = i;
01007 
01008     if (bits_in_b == 1)
01009     {
01010       for (short row2 = m - 1; row2 >= 0; --row2)
01011       {
01012         if (!matrix[row2].any())
01013         {
01014           if (row2 != b_row)
01015           {
01016             rows[b_row] = row2;
01017             rows[row2] = b_row;
01018             if (M_coefficients.test(b_row) != M_coefficients.test(row2))
01019             {
01020               M_coefficients.flip(b_row);
01021               M_coefficients.flip(row2);
01022             }
01023           }
01024         }
01025       }
01026     }
01027 
01028 #if ECC_DEBUGOUTPUT
01029     LibEccDout(dc::polynomial, "After swap: Matrix =");
01030     for (short row2 = m - 1; row2 >= 0; --row2)
01031       LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[rows[row2]]),
01032           &bitset<m>::base2_print_on)
01033           << "  x" << row2 << "   " << (M_coefficients.test(row2) ? '1' : '0')
01034           << "   " << (b.get_bitset().test(row2) ? '1' : '0'));
01035 #endif
01036 
01037     for (unsigned short col = 0; col < m; ++col)
01038     {
01039       unsigned short row = col;
01040       for (; row < m; ++row)
01041       {
01042         unsigned short mr = rows[row];
01043         if (matrix[mr].test(col))
01044         {
01045           for (unsigned short row2 = row + 1; row2 < m; ++row2)
01046           {
01047             unsigned short mr2 = rows[row2];
01048             if (matrix[mr2].test(col))
01049             {
01050               matrix[mr2] ^= matrix[mr];
01051               if (!b.get_bitset().test(row2) && !matrix[mr2].any())
01052               {
01053                 // This could lead to possible problems.  Therefore wipe with row2 instead of row.
01054                 matrix[mr2] = matrix[mr];
01055                 matrix[mr].reset();
01056                 // Undo previous wiping when necessary.
01057                 if (M_coefficients.test(row) != M_coefficients.test(row2))
01058                   for (unsigned short row3 = row + 1; row3 < row2; ++row3)
01059                     M_coefficients.flip(row3);
01060                 if (M_coefficients.test(row2))
01061                   M_coefficients.flip(row);
01062                 // Continue with row2 as wipe row.
01063                 row = row2;
01064                 mr = mr2;
01065               }
01066               else if (M_coefficients.test(row))
01067                 M_coefficients.flip(row2);
01068             }
01069           }
01070 
01071 #if ECC_DEBUGOUTPUT
01072           LibEccDout(dc::polynomial, "After wipe: Matrix =");
01073           for (short row2 = m - 1; row2 >= 0; --row2)
01074             LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[rows[row2]]),
01075                 &bitset<m>::base2_print_on)
01076                 << "  x" << row2 << "   " << (M_coefficients.test(row2) ? '1' : '0')
01077                 << "   " << (b.get_bitset().test(row2) ? '1' : '0'));
01078 #endif
01079 
01080           if (row != col)
01081           {
01082             unsigned short mc = rows[col];
01083             rows[col] = mr;
01084             rows[row] = mc;
01085             if (M_coefficients.test(row) != M_coefficients.test(col))
01086             {
01087               M_coefficients.flip(row);
01088               M_coefficients.flip(col);
01089             }
01090           }
01091 
01092 #if ECC_DEBUGOUTPUT
01093           LibEccDout(dc::polynomial, "After swap: Matrix =");
01094           for (short row2 = m - 1; row2 >= 0; --row2)
01095             LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[rows[row2]]),
01096                 &bitset<m>::base2_print_on)
01097                 << "  x" << row2 << "   " << (M_coefficients.test(row2) ? '1' : '0')
01098                 << "   " << (b.get_bitset().test(row2) ? '1' : '0'));
01099 #endif
01100 
01101           break;
01102         }
01103       }
01104       if (row == m)
01105       {
01106         if (b_row == -1)
01107         {
01108           // Again a possible problem, this row `col' needs to be swapped
01109           // later with another row that we will run into later (if there
01110           // is a solution at all).  See next 'else' block.
01111           LibEccDout(dc::polynomial, "Setting b_row to " << col);
01112           b_row = col;
01113         }
01114         else
01115         {
01116           LibEccDout(dc::polynomial, "Swapping row " << col << " with row " << b_row);
01117           // Now we did run into this row.
01118           // Swap row `col' with `b_row'.
01119           unsigned short mc = rows[b_row];
01120           rows[b_row] = rows[col];
01121           rows[col] = mc;
01122           if (M_coefficients.test(b_row) != M_coefficients.test(col))
01123           {
01124             M_coefficients.flip(b_row);
01125             M_coefficients.flip(col);
01126           }
01127 
01128 #if ECC_DEBUGOUTPUT
01129           LibEccDout(dc::polynomial, "After swap: Matrix =");
01130           for (short row2 = m - 1; row2 >= 0; --row2)
01131             LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[rows[row2]]),
01132                 &bitset<m>::base2_print_on)
01133                 << "  x" << row2 << "   " << (M_coefficients.test(row2) ? '1' : '0')
01134                 << "   " << (b.get_bitset().test(row2) ? '1' : '0'));
01135 #endif
01136 
01137           // Now we need to wipe row `col' again.
01138           for (unsigned short col2 = b_row + 1; col2 < col; ++col2)
01139             if (matrix[mc].test(col2))
01140             {
01141               matrix[mc] ^= matrix[rows[col2]];
01142               if (M_coefficients.test(col2))
01143                 M_coefficients.flip(col);
01144 
01145 #if ECC_DEBUGOUTPUT
01146               LibEccDout(dc::polynomial, "After wipe of row " << col << " with row " << col2 << ": Matrix =");
01147               for (short row2 = m - 1; row2 >= 0; --row2)
01148                 LibEccDout(dc::polynomial, cwprint_using(*static_cast<libecc::bitset_invertible<m, false>*>(&matrix[rows[row2]]),
01149                     &bitset<m>::base2_print_on)
01150                     << "  x" << row2 << "   " << (M_coefficients.test(row2) ? '1' : '0')
01151                     << "   " << (b.get_bitset().test(row2) ? '1' : '0'));
01152 #endif
01153 
01154             }
01155         }
01156       }
01157     }
01158 
01159     for (short i = m - 1; i >= 0; --i)
01160     {
01161       bitset<m> temp = M_coefficients & matrix[rows[i]];
01162       for (short j = m - 1; j > i; --j)
01163         if (temp.test(j))
01164           M_coefficients.flip(i);
01165     }
01166   }
01167 
01168 template<unsigned int m, unsigned int k>
01169   inline bool
01170   operator==(polynomial<m, k> const& p1, polynomial<m, k> const& p2)
01171   {
01172     return p1.M_coefficients == p2.M_coefficients;
01173   }
01174 
01175 template<unsigned int m, unsigned int k>
01176   inline bool
01177   operator!=(polynomial<m, k> const& p1, polynomial<m, k> const& p2)
01178   {
01179     return p1.M_coefficients != p2.M_coefficients;
01180   }
01181 
01182 template<unsigned int m, unsigned int k>
01183   inline Operator::bitsetExpression<m, false, false, Operator::bitsetXOR>
01184   operator+(polynomial<m, k> const& p1, polynomial<m, k> const& p2)
01185   {
01186     return Operator::bitsetExpression<m, false, false, Operator::bitsetXOR>(p1.M_coefficients, p2.M_coefficients);
01187   }
01188 
01189 template<unsigned int m, unsigned int k>
01190   inline Operator::bitsetExpression<m, false, false, Operator::bitsetXOR>
01191   operator-(polynomial<m, k> const& p1, polynomial<m, k> const& p2)
01192   {
01193     return Operator::bitsetExpression<m, false, false, Operator::bitsetXOR>(p1.M_coefficients, p2.M_coefficients);
01194   }
01195 
01196 template<unsigned int m, unsigned int k>
01197   inline polynomial<m, k>
01198   operator*(polynomial<m, k> const& p1, polynomial<m, k> const& p2)
01199   {
01200     polynomial<m, k> result;
01201     p1.multiply_with(p2, result.M_coefficients);
01202     return result;
01203   }
01204 
01205 template<unsigned int m, unsigned int k>
01206   inline polynomial<m, k>
01207   operator/(polynomial<m, k> const& e1, polynomial<m, k> const& e2)
01208   {
01209     polynomial<m, k> tmp(e1);
01210     tmp /= e2;
01211     return tmp;
01212   }
01213 
01214 template<unsigned int m, unsigned int k>
01215   std::ostream& operator<<(std::ostream& os, polynomial<m, k> const& p)
01216   {
01217     p.M_coefficients.base2_print_on(os);
01218     return os;
01219   }
01220 
01221 } // namespace libecc
01222 
01223 #include <libecc/square.hcc>    // File with different copyright.
01224 
01225 #endif // LIBECC_POLYNOMIAL_H
Copyright © 2002 Carlo Wood.  All rights reserved.