verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey )
{
  gpg_err_code_t rc = 0;
  gcry_mpi_t w, u1, u2, v;
  gcry_mpi_t base[3];
  gcry_mpi_t ex[3];
  gcry_mpi_t hash;
  unsigned int nbits;

  if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
    return GPG_ERR_BAD_SIGNATURE; /* Assertion	0 < r < n  failed.  */
  if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
    return GPG_ERR_BAD_SIGNATURE; /* Assertion	0 < s < n  failed.  */

  nbits = mpi_get_nbits (pkey->q);
  rc = _gcry_dsa_normalize_hash (input, &hash, nbits);
  if (rc)
    return rc;

  w  = mpi_alloc( mpi_get_nlimbs(pkey->q) );
  u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
  u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
  v  = mpi_alloc( mpi_get_nlimbs(pkey->p) );

  /* w = s^(-1) mod q */
  mpi_invm( w, s, pkey->q );

  /* u1 = (hash * w) mod q */
  mpi_mulm( u1, hash, w, pkey->q );

  /* u2 = r * w mod q  */
  mpi_mulm( u2, r, w, pkey->q );

  /* v =  g^u1 * y^u2 mod p mod q */
  base[0] = pkey->g; ex[0] = u1;
  base[1] = pkey->y; ex[1] = u2;
  base[2] = NULL;    ex[2] = NULL;
  mpi_mulpowm( v, base, ex, pkey->p );
  mpi_fdiv_r( v, v, pkey->q );

  if (mpi_cmp( v, r ))
    {
      if (DBG_CIPHER)
        {
          log_mpidump ("     i", input);
          log_mpidump ("     h", hash);
          log_mpidump ("     v", v);
          log_mpidump ("     r", r);
          log_mpidump ("     s", s);
        }
      rc = GPG_ERR_BAD_SIGNATURE;
    }

  mpi_free(w);
  mpi_free(u1);
  mpi_free(u2);
  mpi_free(v);
  if (hash != input)
    mpi_free (hash);

  return rc;
}
verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey )
{
  gpg_err_code_t rc = 0;
  gcry_mpi_t w, u1, u2, v;
  gcry_mpi_t base[3];
  gcry_mpi_t ex[3];
  gcry_mpi_t hash;
  unsigned int nbits;

  if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
    return GPG_ERR_BAD_SIGNATURE;  
  if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
    return GPG_ERR_BAD_SIGNATURE;  

  nbits = mpi_get_nbits (pkey->q);
  rc = _gcry_dsa_normalize_hash (input, &hash, nbits);
  if (rc)
    return rc;

  w  = mpi_alloc( mpi_get_nlimbs(pkey->q) );
  u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
  u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
  v  = mpi_alloc( mpi_get_nlimbs(pkey->p) );

   
  mpi_invm( w, s, pkey->q );

   
  mpi_mulm( u1, hash, w, pkey->q );

   
  mpi_mulm( u2, r, w, pkey->q );

   
  base[0] = pkey->g; ex[0] = u1;
  base[1] = pkey->y; ex[1] = u2;
  base[2] = NULL;    ex[2] = NULL;
  mpi_mulpowm( v, base, ex, pkey->p );
  mpi_fdiv_r( v, v, pkey->q );

  if (mpi_cmp( v, r ))
    {
      if (DBG_CIPHER)
        {
          log_mpidump ("     i", input);
          log_mpidump ("     h", hash);
          log_mpidump ("     v", v);
          log_mpidump ("     r", r);
          log_mpidump ("     s", s);
        }
      rc = GPG_ERR_BAD_SIGNATURE;
    }

  mpi_free(w);
  mpi_free(u1);
  mpi_free(u2);
  mpi_free(v);
  if (hash != input)
    mpi_free (hash);

  return rc;
}