// Path: src/main/java/com/github/aelstad/keccakj/io/BitInputStream.java
// public abstract class BitInputStream extends InputStream {		
// 	@Override
// 	public abstract void close();
// 	
// 	
// 	@Override
// 	public int read(byte[] b, int off, int len) {
// 		return (int) (readBits(b, ((long)off)<<3, ((long)len)<<3)>>3);
// 	}
// 	
// 	/**
// 	 * Transform input to output with the input stream as a keystream 
// 	 * 
// 	 * @param input Input byte-array
// 	 * @param inputOff Input offset
// 	 * @param output Output byte-array
// 	 * @param outputOff Output offset
// 	 * @param len length in bytes
// 	 * @return Number of bytes transformed
// 	 */
// 	public int transform(byte[] input, int inputOff, byte[] output, int outputOff, int len) {
// 		return (int) (transformBits(input, ((long)inputOff)<<3, output, ((long)outputOff)<<3, ((long)len)<<3)>>3);
// 	}
// 
// 
// 	@Override
// 	public int read(byte[] b)  {
// 		return this.read(b, 0, b.length)>>3;
// 	}
// 	
// 	/**
// 	 * Transform input to output using the input stream as a keystream 
// 	 * 
// 	 * @param input Input byte array
// 	 * @param output Output byte array
// 	 * 
// 	 * @return Number of bytes transformed
// 	 */
// 	public int transform(byte[] input, byte[] output) {
// 		return (int) (transformBits(input, 0l, output, 0l, ((long)input.length)<<3)>>3);
// 	}
// 
// 
// 	@Override
// 	public int read() {
// 		byte[] buf = new byte[1];
// 		readBits(buf, 0, 8);
// 		
// 		return ((int) buf[0]) & 0xff;		
// 	}
// 
// 
// 	public abstract long readBits(byte[] arg, long bitOff, long bitLen);
// 	
// 	/**
// 	 * Transform input to output using the input stream as a keystream 
// 	 * 
// 	 * @param input Input byte array
// 	 * @param inputOff Input offset in bits
// 	 * @param output Output byte array
// 	 * @param outputOff Output offset in bits
// 	 * @param bitLen Number of bits
// 	 * @return Number of bits transformed
// 	 */
// 	public abstract long transformBits(byte[] input, long inputOff, byte[] output, long outputOff, long bitLen);
// }
// 
// Path: src/main/java/com/github/aelstad/keccakj/io/BitOutputStream.java
// public abstract class BitOutputStream extends OutputStream {
// 
// 	@Override
// 	public abstract void close();
// 
// 	@Override
// 	public void write(byte[] b, int off, int len) {
// 		writeBits(b, ((long) (off))<<3, ((long)len)<<3);
// 	}
// 
// 	@Override
// 	public void write(byte[] b) {
// 		write(b, 0, b.length);
// 	}
// 	
// 	@Override
// 	public void write(int b) {
// 		writeBits(new byte[] { (byte) b }, 0, 8);
// 	}
// 
// 	public abstract void writeBits(byte[] arg, long bitOff, long bitLen);
// 	
// }


import java.security.MessageDigest;
import com.github.aelstad.keccakj.io.BitInputStream;
import com.github.aelstad.keccakj.io.BitOutputStream;
package com.github.aelstad.keccakj.core;



public abstract class AbstractKeccakMessageDigest extends MessageDigest {

	KeccakSponge keccakSponge;
	BitOutputStream absorbStream;
	int digestLength;

	/**
	 * Security level in bits is min(capacity/2,digestLength*8).
	 *
	 * @param algorithm Algorithm name
	 * @param capacityInBits Keccack capacity in bits. Must be a multiple of 8.
	 * @param digestLength Length of digest in bytes
	 * @param domainPadding Domain padding value
	 * @param domainPaddingBitLength Domain padding bits
	 */
	public AbstractKeccakMessageDigest(String algorithm, int capacityInBits, int digestLength, byte domainPadding, int domainPaddingBitLength)
	{
		super(algorithm);
		this.keccakSponge = new KeccakSponge(capacityInBits, domainPadding, domainPaddingBitLength);

		this.absorbStream = keccakSponge.getAbsorbStream();
		this.digestLength = digestLength;
	}

	@Override
	protected byte[] engineDigest() {
		absorbStream.close();

		byte[] rv = new byte[digestLength];
		BitInputStream bis = keccakSponge.getSqueezeStream();
// Path: src/main/java/com/github/aelstad/keccakj/io/BitInputStream.java
// public abstract class BitInputStream extends InputStream {		
// 	@Override
// 	public abstract void close();
// 	
// 	
// 	@Override
// 	public int read(byte[] b, int off, int len) {
// 		return (int) (readBits(b, ((long)off)<<3, ((long)len)<<3)>>3);
// 	}
// 	
// 	/**
// 	 * Transform input to output with the input stream as a keystream 
// 	 * 
// 	 * @param input Input byte-array
// 	 * @param inputOff Input offset
// 	 * @param output Output byte-array
// 	 * @param outputOff Output offset
// 	 * @param len length in bytes
// 	 * @return Number of bytes transformed
// 	 */
// 	public int transform(byte[] input, int inputOff, byte[] output, int outputOff, int len) {
// 		return (int) (transformBits(input, ((long)inputOff)<<3, output, ((long)outputOff)<<3, ((long)len)<<3)>>3);
// 	}
// 
// 
// 	@Override
// 	public int read(byte[] b)  {
// 		return this.read(b, 0, b.length)>>3;
// 	}
// 	
// 	/**
// 	 * Transform input to output using the input stream as a keystream 
// 	 * 
// 	 * @param input Input byte array
// 	 * @param output Output byte array
// 	 * 
// 	 * @return Number of bytes transformed
// 	 */
// 	public int transform(byte[] input, byte[] output) {
// 		return (int) (transformBits(input, 0l, output, 0l, ((long)input.length)<<3)>>3);
// 	}
// 
// 
// 	@Override
// 	public int read() {
// 		byte[] buf = new byte[1];
// 		readBits(buf, 0, 8);
// 		
// 		return ((int) buf[0]) & 0xff;		
// 	}
// 
// 
// 	public abstract long readBits(byte[] arg, long bitOff, long bitLen);
// 	
// 	/**
// 	 * Transform input to output using the input stream as a keystream 
// 	 * 
// 	 * @param input Input byte array
// 	 * @param inputOff Input offset in bits
// 	 * @param output Output byte array
// 	 * @param outputOff Output offset in bits
// 	 * @param bitLen Number of bits
// 	 * @return Number of bits transformed
// 	 */
// 	public abstract long transformBits(byte[] input, long inputOff, byte[] output, long outputOff, long bitLen);
// }
// 
// Path: src/main/java/com/github/aelstad/keccakj/io/BitOutputStream.java
// public abstract class BitOutputStream extends OutputStream {
// 
// 	@Override
// 	public abstract void close();
// 
// 	@Override
// 	public void write(byte[] b, int off, int len) {
// 		writeBits(b, ((long) (off))<<3, ((long)len)<<3);
// 	}
// 
// 	@Override
// 	public void write(byte[] b) {
// 		write(b, 0, b.length);
// 	}
// 	
// 	@Override
// 	public void write(int b) {
// 		writeBits(new byte[] { (byte) b }, 0, 8);
// 	}
// 
// 	public abstract void writeBits(byte[] arg, long bitOff, long bitLen);
// 	
// }


// Path: src/main/java/com/github/aelstad/keccakj/core/AbstractKeccakMessageDigest.java
import java.security.MessageDigest;
import com.github.aelstad.keccakj.io.BitInputStream;
import com.github.aelstad.keccakj.io.BitOutputStream;

package com.github.aelstad.keccakj.core;



public abstract class AbstractKeccakMessageDigest extends MessageDigest {

	KeccakSponge keccakSponge;
	BitOutputStream absorbStream;
	int digestLength;

	/**
	 * Security level in bits is min(capacity/2,digestLength*8).
	 *
	 * @param algorithm Algorithm name
	 * @param capacityInBits Keccack capacity in bits. Must be a multiple of 8.
	 * @param digestLength Length of digest in bytes
	 * @param domainPadding Domain padding value
	 * @param domainPaddingBitLength Domain padding bits
	 */
	public AbstractKeccakMessageDigest(String algorithm, int capacityInBits, int digestLength, byte domainPadding, int domainPaddingBitLength)
	{
		super(algorithm);
		this.keccakSponge = new KeccakSponge(capacityInBits, domainPadding, domainPaddingBitLength);

		this.absorbStream = keccakSponge.getAbsorbStream();
		this.digestLength = digestLength;
	}

	@Override
	protected byte[] engineDigest() {
		absorbStream.close();

		byte[] rv = new byte[digestLength];
		BitInputStream bis = keccakSponge.getSqueezeStream();
		bis.read(rv);