package proof;

import java.io.*;
import java.util.*;
import java.security.*;

import sdsi.*;
import proof.*;
import servlet.*;
import Tools.*;

/**
 * An authenticator closure that exploits the fact that a public key hash
 * is, duh, just shorthand for a public key.
 *
 * @deprecated part of the original {@link Prover} class.
 * {@link Prover2} is the tool clients should use now.
 */
public class HashEquivalence
	implements AuthClosure {

	Subject subject;
	SDSIPrincipal issuer;
	boolean issuerIsPublicKey;

	/**
	 * public key is issuer, hash is subject
	 */
	public HashEquivalence(SDSIPublicKey issuer, String hashType) {
		this.issuer = issuer;
		this.subject = makeHash(hashType, issuer);
		issuerIsPublicKey = true;
	}

	/**
	 * public key is subject, hash is subject
	 */
	public HashEquivalence(String hashType, SDSIPublicKey subject) {
		this.issuer = makeHash(hashType, subject);
		this.subject = subject;
		issuerIsPublicKey = false;
	}
	
	Hash makeHash(String hashType, SDSIPublicKey pub) {
		try {
			return new Hash(hashType, pub);
		} catch (NoSuchAlgorithmException ex) {
			return null;
		}
	}

	/** who is getting to do the speaking */
	public Subject getSubject() {
		return subject;
	}

	/** who is being spoken for */
	public Subject getIssuer() {
		return issuer;
	}

	/**
	 * That some hash of this key is the hash of this key is "self-evident"
	 * and requires no explicit proof.  The proof verifier will have to
	 * verify the fact, but there's no sense in passing an explicit fact
	 * around; the point of a hash is to save space. :v)
	 *
	 * TODO: That's not the whole story: it may be obvious, but sometimes
	 * we may have to provide the public key in question so that the verifier
	 * can, for example, discover that a particular sha1 hash turns out to
	 * be equivalent to (a hash of the same object as) some other md5 hash.
	 */
	public Proof getProof(SDSIPrincipal issuer, Subject subject) {
		Assert.assert(issuer.equals(this.issuer));
		Assert.assert(subject.equals(this.subject));
		return null;	// no proof needed
	}

	public boolean equals(Object o) {
		if (o instanceof HashEquivalence) {
			HashEquivalence he = (HashEquivalence) o;
			if (he.issuerIsPublicKey != issuerIsPublicKey) {
				return false;
			}
			// compare on the hash so that we take the hash type {md5, sha1}
			// into account
			if (issuerIsPublicKey) {
				return he.subject.equals(subject);
			} else {
				return he.issuer.equals(issuer);
			}
		}
		return false;
	}

	public int hashCode() {
		return subject.hashCode();
	}

	public boolean isUsefulForAuth(Tag authTag) {
		return true;
	}
}
