package org.bouncycastle.crypto.signers;

import java.math.BigInteger;
import java.security.SecureRandom;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DSA;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECPoint;

/**
 * EC-DSA as described in X9.62
 */
public class ECDSASigner
    implements ECConstants, DSA
{
    private final DSAKCalculator kCalculator;

    private ECKeyParameters key;
    private SecureRandom    random;

    /**
     * Default configuration, random K values.
     */
    public ECDSASigner()
    {
        this.kCalculator = new RandomDSAKCalculator();
    }

    /**
     * Configuration with an alternate, possibly deterministic calculator of K.
     *
     * @param kCalculator a K value calculator.
     */
    public ECDSASigner(DSAKCalculator kCalculator)
    {
        this.kCalculator = kCalculator;
    }

    public void init(
        boolean                 forSigning,
        CipherParameters        param)
    {
        if (forSigning)
        {
            if (param instanceof ParametersWithRandom)
            {
                ParametersWithRandom    rParam = (ParametersWithRandom)param;

                this.random = rParam.getRandom();
                this.key = (ECPrivateKeyParameters)rParam.getParameters();
            }
            else
            {
                this.random = new SecureRandom();
                this.key = (ECPrivateKeyParameters)param;
            }
        }
        else
        {
            this.key = (ECPublicKeyParameters)param;
        }
    }

    // 5.3 pg 28
    /**
     * generate a signature for the given message using the key we were
     * initialised with. For conventional DSA the message should be a SHA-1
     * hash of the message of interest.
     *
     * @param message the message that will be verified later.
     */
    public BigInteger[] generateSignature(
        byte[] message)
    {
        BigInteger n = key.getParameters().getN();
        BigInteger e = calculateE(n, message);
        BigInteger r = null;
        BigInteger s = null;

        if (kCalculator.isDeterministic())
        {
            kCalculator.init(n, ((ECPrivateKeyParameters)key).getD(), message);
        }
        else
        {
            kCalculator.init(n, random);
        }

        // 5.3.2
        do // generate s
        {
            BigInteger k = null;

            do // generate r
            {
                k = kCalculator.nextK();

                ECPoint p = key.getParameters().getG().multiply(k).normalize();

                // 5.3.3
                BigInteger x = p.getAffineXCoord().toBigInteger();

                r = x.mod(n);
            }
            while (r.equals(ZERO));

            BigInteger d = ((ECPrivateKeyParameters)key).getD();

            s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
        }
        while (s.equals(ZERO));

        BigInteger[]  res = new BigInteger[2];

        res[0] = r;
        res[1] = s;

        return res;
    }

    // 5.4 pg 29
    /**
     * return true if the value r and s represent a DSA signature for
     * the passed in message (for standard DSA the message should be
     * a SHA-1 hash of the real message to be verified).
     */
    public boolean verifySignature(
        byte[]      message,
        BigInteger  r,
        BigInteger  s)
    {
        BigInteger n = key.getParameters().getN();
        BigInteger e = calculateE(n, message);

        // r in the range [1,n-1]
        if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0)
        {
            return false;
        }

        // s in the range [1,n-1]
        if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0)
        {
            return false;
        }

        BigInteger c = s.modInverse(n);

        BigInteger u1 = e.multiply(c).mod(n);
        BigInteger u2 = r.multiply(c).mod(n);

        ECPoint G = key.getParameters().getG();
        ECPoint Q = ((ECPublicKeyParameters)key).getQ();

        ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2).normalize();

        // components must be bogus.
        if (point.isInfinity())
        {
            return false;
        }

        BigInteger v = point.getAffineXCoord().toBigInteger().mod(n);

        return v.equals(r);
    }

    private BigInteger calculateE(BigInteger n, byte[] message)
    {
        int log2n = n.bitLength();
        int messageBitLength = message.length * 8;

        BigInteger e = new BigInteger(1, message);
        if (log2n < messageBitLength)
        {
            e = e.shiftRight(messageBitLength - log2n);
        }
        return e;
    }
}

@@ -185,16 +185,74 @@
 to.DSA;%0A
+import org.bouncycastle.crypto.params.ECDomainParameters;%0A
 import o
@@ -606,21 +606,125 @@
 th.ec.EC
-Point
+Multiplier;%0Aimport org.bouncycastle.math.ec.ECPoint;%0Aimport org.bouncycastle.math.ec.FixedPointCombMultiplier
 ;%0A%0A/**%0A 
@@ -2401,36 +2401,45 @@
   %7B%0A        
-BigInteger n
+ECDomainParameters ec
  = key.getPa
@@ -2440,32 +2440,59 @@
 .getParameters()
+;%0A        BigInteger n = ec
 .getN();%0A       
@@ -2554,45 +2554,48 @@
 ger 
-r = null;%0A        BigInteger s = null
+d = ((ECPrivateKeyParameters)key).getD()
 ;%0A%0A 
@@ -2682,44 +2682,9 @@
 (n, 
-((ECPrivateKeyParameters)key).getD()
+d
 , me
@@ -2768,32 +2768,134 @@
 om);%0A        %7D%0A%0A
+        BigInteger r, s;%0A%0A        ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();%0A%0A
         // 5.3.2
@@ -2958,17 +2958,9 @@
 er k
- = null;%0A
+;
 %0A   
@@ -3073,44 +3073,48 @@
 p = 
-key.getParameters().getG().multiply(
+basePointMultiplier.multiply(ec.getG(), 
 k).n
@@ -3171,20 +3171,9 @@
     
-BigInteger x
+r
  = p
@@ -3209,32 +3209,8 @@
 er()
-;%0A%0A                r = x
 .mod
@@ -3269,74 +3269,8 @@
 );%0A%0A
-            BigInteger d = ((ECPrivateKeyParameters)key).getD();%0A%0A
     
@@ -3391,107 +3391,39 @@
     
-BigInteger%5B%5D  res = new BigInteger%5B2%5D;%0A%0A        res%5B0%5D = r;%0A        res%5B1%5D = s;%0A%0A        return res
+return new BigInteger%5B%5D%7B r, s %7D
 ;%0A  
@@ -3781,28 +3781,37 @@
         
-BigInteger n
+ECDomainParameters ec
  = key.g
@@ -3820,24 +3820,51 @@
 Parameters()
+;%0A        BigInteger n = ec
 .getN();%0A   
@@ -4338,35 +4338,18 @@
 int G = 
-key.getParameters()
+ec
 .getG();

Use fixed-point comb for multiplying by the base-point