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

#include <botan/dsa.h>
#include <botan/numthry.h>
#include <botan/keypair.h>

namespace Botan {

/*************************************************
* DSA_PublicKey Constructor                      *
*************************************************/
DSA_PublicKey::DSA_PublicKey(const DL_Group& domain, const BigInt& key)
   {
   dl_initialize(domain, key);
   powermod_g_p = FixedBase_Exp(group_g(), group_p());
   powermod_y_p = FixedBase_Exp(y, group_p());
   }

/*************************************************
* DSA Verification Function                      *
*************************************************/
bool DSA_PublicKey::verify(const byte msg[], u32bit msg_len,
                           const byte sig[], u32bit sig_len) const
   {
   const BigInt& q = group_q();
   const BigInt& p = group_p();
   if(sig_len != 2*q.bytes() || msg_len > q.bytes())
      return false;

   BigInt t1(msg, msg_len);
   BigInt r(sig, q.bytes());
   BigInt s(sig + q.bytes(), q.bytes());

   if(r.is_zero() || s.is_zero() || r >= q || s >= q)
      return false;

   BigInt w = inverse_mod(s, q);

   BigInt u1 = w, u2 = w;
   u1 *= t1; u2 *= r;
   u1 %= q;  u2 %= q;
   BigInt v = (powermod_g_p(u1) * powermod_y_p(u2)) % p;
   return (v % q == r);
   }

/*************************************************
* Decode X.509 DSA parameters                    *
*************************************************/
void DSA_PublicKey::BER_decode_params(DataSource& source)
   {
   group.BER_decode(source, DL_Group::ANSI_X9_57);
   }

/*************************************************
* Return the parameters in X.509 encoding        *
*************************************************/
SecureVector<byte> DSA_PublicKey::DER_encode_params() const
   {
   return group.DER_encode(DL_Group::ANSI_X9_57);
   }

/*************************************************
* Decode a X.509 public key encoding             *
*************************************************/
void DSA_PublicKey::BER_decode_pub(DataSource& source)
   {
   DL_Scheme_PublicKey::BER_decode_pub(source);
   powermod_g_p = FixedBase_Exp(group_g(), group_p());
   powermod_y_p = FixedBase_Exp(y, group_p());
   }

/*************************************************
* Return the name of this algorithm              *
*************************************************/
std::string DSA_PublicKey::algo_name() const
   {
   return "DSA";
   }

/*************************************************
* Return the maximum input size in bits          *
*************************************************/
u32bit DSA_PublicKey::max_input_bits() const
   {
   return group_q().bits();
   }

/*************************************************
* Return the size of each portion of the sig     *
*************************************************/
u32bit DSA_PublicKey::message_part_size() const
   {
   const BigInt& q = group_q();
   return q.bytes();
   }

/*************************************************
* DSA_PrivateKey Constructor                     *
*************************************************/
DSA_PrivateKey::DSA_PrivateKey(const DL_Group& domain) :
   DSA_PublicKey(domain, 0)
   {
   x = random_integer(2, group_q() - 1, LongTermKey);
   y = powermod_g_p(x);
   powermod_y_p = FixedBase_Exp(y, group_p());
   if(!check_params())
      throw Self_Test_Failure(algo_name() + " private key generation failed");
   }

/*************************************************
* DSA_PrivateKey Constructor                     *
*************************************************/
DSA_PrivateKey::DSA_PrivateKey(const DL_Group& domain,
                               const BigInt& priv, const BigInt& pub) :
   DSA_PublicKey(domain, pub)
   {
   x = priv;
   if(x <= 1 || x >= group_q())
      throw Invalid_Argument(algo_name() + ": Invalid private key");
   }

/*************************************************
* DSA Signature Operation                        *
*************************************************/
SecureVector<byte> DSA_PrivateKey::sign(const byte in[], u32bit len) const
   {
   const BigInt& q = group_q();
   BigInt t1(in, len);

   while(true)
      {
      BigInt k;
      do
         k.randomize(q.bits(), SessionKey);
      while(k >= q);

      BigInt r = powermod_g_p(k) % q;
      BigInt s = (inverse_mod(k, q) * mul_add(x, r, t1)) % q;

      if(r.is_zero() || s.is_zero())
         continue;

      SecureVector<byte> output(2*q.bytes());
      r.binary_encode(output + (output.size() / 2 - r.bytes()));
      s.binary_encode(output + (output.size() - s.bytes()));
      return output;
      }
   }

/*************************************************
* Decode a PKCS #8 DSA private key               *
*************************************************/
void DSA_PrivateKey::BER_decode_priv(DataSource& source)
   {
   DL_Scheme_PrivateKey::BER_decode_priv(source);
   powermod_g_p = FixedBase_Exp(group_g(), group_p());
   y = powermod_g_p(x);
   powermod_y_p = FixedBase_Exp(y, group_p());
   }

/*************************************************
* Check Private DSA Parameters                   *
*************************************************/
bool DSA_PrivateKey::check_params() const
   {
   if(!DL_Scheme_PublicKey::check_params())
      return false;

   if(x <= 1 || y <= 1 || x >= group_p() || y >= group_p())
      return false;
   if(y != powermod_g_p(x))
      return false;

   try {
      KeyPair::check_key(get_pk_signer(*this, "EMSA1(SHA-1)"),
                         get_pk_verifier(*this, "EMSA1(SHA-1)")
         );
      }
   catch(Self_Test_Failure)
      {
      return false;
      }

   return true;
   }

}
