/*************************************************
* Barrett Reducer Source File                    *
* (C) 1999-2003 The Botan Project                *
*************************************************/

#include <botan/barrett.h>
#include <botan/numthry.h>
#include <botan/mp_types.h>

namespace Botan {

/*************************************************
* Precompute values                              *
*************************************************/
BarrettReducer::BarrettReducer(const BigInt& mod) : ModularReducer(mod)
   {
   k = modulus.sig_words();
   mu.set_bit(MP_WORD_BITS * 2 * k);
   mu /= modulus;
   max_bits = MP_WORD_BITS * 2 * k;
   b_to_k1.set_bit(MP_WORD_BITS * (k+1));

   if(mu.size() > 8 && !power_of_2(mu.size()))
      mu.grow_reg((1 << high_bit(mu.size())) - mu.size());
   }

/*************************************************
* Barrett Reduction                              *
*************************************************/
BigInt BarrettReducer::reduce(const BigInt& n) const
   {
   if(n.is_positive() && n < modulus)
      return n;
   if(n.bits() > max_bits)
      return (n % modulus);

   a = n;
   a.set_sign(BigInt::Positive);
   a >>= (MP_WORD_BITS * (k - 1));
   a *= mu;
   a >>= (MP_WORD_BITS * (k + 1));
   a *= modulus;
   for(u32bit j = k + 1; j < a.size(); j++)
      a[j] = 0;

   b = n;
   b.set_sign(BigInt::Positive);
   for(u32bit j = k + 1; j < b.size(); j++)
      b[j] = 0;
   b -= a;

   if(b.is_negative())
      b += b_to_k1;
   while(b >= modulus)
      b -= modulus;

   if(n.is_negative() && b.is_nonzero())
      { b = modulus - b; }
   return b;
   }

}
