
import java.math.BigInteger;
import java.io.Serializable;
import java.security.MessageDigest;
import java.util.StringTokenizer;

/**
 * Created by IntelliJ IDEA.
 * User: Johnson Gong
 * Date: 2006-3-10
 * Time: 18:30:17
 * To change this template use File | Settings | File Templates.
 */
public class SignedObject_RD implements Serializable  {
    private Message message;
    //private BigInteger p;
    //private BigInteger q;
    //private BigInteger phi_N;
    private BigInteger N;
    //private BigInteger k;
    private BigInteger a;
    private final int CERTAINTY = 30;


    public Message getMessage() {
        return message;
    }

    public BigInteger getSignature() {
        return signature;
    }

    private BigInteger signature;


    public SignedObject_RD (Message m,BigInteger privateKey_p, BigInteger privateKey_q, BigInteger a){
        this.message = m;
        N = privateKey_p.multiply(privateKey_q);
        BigInteger phi_N = N.subtract(privateKey_p).subtract(privateKey_q).add(BigInteger.ONE);
        this.a = a;
        helper_Sign(phi_N);

    }
    private BigInteger getPrime(BigInteger n, BigInteger N){
        BigInteger two = BigInteger.ONE.add(BigInteger.ONE);
        if (n.mod(new BigInteger("2")).compareTo(BigInteger.ZERO) == 0){
            n = n.add(BigInteger.ONE).mod(N);
        }
        while(!n.isProbablePrime(CERTAINTY)){
            n = n.add(two).mod(N);
        }
        return n;
    }
    private BigInteger getPositiveValue(BigInteger n){
        if (n.compareTo(BigInteger.ZERO)== -1){
            return n.negate();
        }
        else
            return n;
    }
    private void helper_Sign(BigInteger phi_N){
        System.out.println("Signing.....");
        try{
            MessageDigest md = MessageDigest.getInstance("SHA1");
            BigInteger h1 = BigInteger.ONE;

            BigInteger senderHash = (new BigInteger(md.digest(message.getSender().getBytes())));
            senderHash = this.getPositiveValue(senderHash);
            senderHash = senderHash.mod(phi_N);
            senderHash = getPrime(senderHash,phi_N);

            BigInteger receiverHash = (new BigInteger(md.digest(message.getReceiver().getBytes())));
            receiverHash = this.getPositiveValue(receiverHash);
            receiverHash = receiverHash.mod(phi_N);
            receiverHash = getPrime(receiverHash,phi_N);

            Long tsToHash = new Long(message.getTimestamp().getTimeInMillis());
            BigInteger timestamp = (new BigInteger(md.digest(tsToHash.toString().getBytes())));
            timestamp = this.getPositiveValue(timestamp);
            timestamp = timestamp.mod(phi_N);
            timestamp = getPrime(timestamp,phi_N);

            h1 = h1.multiply(senderHash).mod(phi_N).multiply(receiverHash).mod(phi_N).multiply(timestamp).mod(phi_N);

            System.out.println("h1 = " + h1.toString(16));
            StringTokenizer st = new StringTokenizer(message.getChat());
            while(st.hasMoreTokens()){
                BigInteger word = (new BigInteger(md.digest(st.nextToken().getBytes())));
                word = this.getPositiveValue(word);
                //System.out.println("word before mod =" + word.toString(16) );
                word = word.mod(phi_N);
                //System.out.println("word after mod =" + word.toString(16));
                word = getPrime(word, phi_N);
                h1 = h1.multiply(word).mod(phi_N);
            }
            System.out.println("h1 = " + h1.toString(16));

            signature = a.modPow(h1.modInverse(phi_N),N);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    public boolean verify(BigInteger N, BigInteger a){
        System.out.println("Verifying.....");

        try {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            //BigInteger h1 = BigInteger.ONE;
            BigInteger result = signature;

            BigInteger senderHash = (new BigInteger(md.digest(message.getSender().getBytes())));
            senderHash = this.getPositiveValue(senderHash);
            senderHash = senderHash.mod(N);
            senderHash = getPrime(senderHash,N);
            result = result.modPow(senderHash,N);

            BigInteger receiverHash = (new BigInteger(md.digest(message.getReceiver().getBytes())));
            receiverHash = this.getPositiveValue(receiverHash);
            receiverHash = receiverHash.mod(N);
            receiverHash = getPrime(receiverHash,N);
            result = result.modPow(receiverHash, N);

            Long tsToHash = new Long(message.getTimestamp().getTimeInMillis());
            BigInteger timestamp = (new BigInteger(md.digest(tsToHash.toString().getBytes())));
            timestamp = this.getPositiveValue(timestamp);
            timestamp = timestamp.mod(N);
            timestamp = getPrime(timestamp,N);
            result = result.modPow(timestamp, N);

            StringTokenizer st = new StringTokenizer(message.getChat());


            while (st.hasMoreTokens()) {
                BigInteger word = new BigInteger(md.digest(st.nextToken().getBytes()));
                word = this.getPositiveValue(word);
                word = word.mod(N);
                word = getPrime(word,N);
                result = result.modPow(word,N);
            }

            return (result.compareTo(a) == 0);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    public BigInteger getSquealSig(int i){
        try {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            //BigInteger h1 = BigInteger.ONE;
            BigInteger result = signature;

            BigInteger senderHash = (new BigInteger(md.digest(message.getSender().getBytes())));
            senderHash = this.getPositiveValue(senderHash);
            senderHash = senderHash.mod(N);
            senderHash = getPrime(senderHash, N);
            result = result.modPow(senderHash, N);

            BigInteger receiverHash = (new BigInteger(md.digest(message.getReceiver().getBytes())));
            receiverHash = this.getPositiveValue(receiverHash);
            receiverHash = receiverHash.mod(N);
            receiverHash = getPrime(receiverHash, N);
            result = result.modPow(receiverHash, N);

            Long tsToHash = new Long(message.getTimestamp().getTimeInMillis());
            BigInteger timestamp = (new BigInteger(md.digest(tsToHash.toString().getBytes())));
            timestamp = this.getPositiveValue(timestamp);
            timestamp = timestamp.mod(N);
            timestamp = getPrime(timestamp, N);
            result = result.modPow(timestamp, N);

            StringTokenizer st = new StringTokenizer(message.getChat());

            int j = 0;
            while (st.hasMoreTokens()) {
                String s = st.nextToken();
                if (i == j) continue;
                BigInteger word = new BigInteger(md.digest(s.getBytes()));
                word = this.getPositiveValue(word);
                word = word.mod(N);
                word = getPrime(word, N);
                result = result.modPow(word, N);
                j++;
            }
            return result;

            //return (result.compareTo(a) == 0);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }
}
