// $Id: Luffa512.java 235 2010-06-18 15:31:36Z tp $

package fr.cryptohash;

/**
 * <p>This class implements Luffa-512 digest algorithm under the
 * {@link Digest} API.</p>
 *
 * <pre>
 * ==========================(LICENSE BEGIN)============================
 *
 * Copyright (c) 2007-2010  Projet RNRT SAPHIR
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * ===========================(LICENSE END)=============================
 * </pre>
 *
 * @version   $Revision: 235 $
 * @author    Thomas Pornin &lt;thomas.pornin@cryptolog.com&gt;
 */

public class Luffa512 extends DigestEngine {

	private static final int[] IV = {
		0x6d251e69, 0x44b051e0, 0x4eaa6fb4, 0xdbf78465,
		0x6e292011, 0x90152df4, 0xee058139, 0xdef610bb,
		0xc3b44b95, 0xd9d2f256, 0x70eee9a0, 0xde099fa3,
		0x5d9b0557, 0x8fc944b3, 0xcf1ccf0e, 0x746cd581,
		0xf7efc89d, 0x5dba5781, 0x04016ce5, 0xad659c05,
		0x0306194f, 0x666d1836, 0x24aa230a, 0x8b264ae7,
		0x858075d5, 0x36d79cce, 0xe571f7d7, 0x204b1f67,
		0x35870c6a, 0x57e9e923, 0x14bcb808, 0x7cde72ce,
		0x6c68e9be, 0x5ec41e22, 0xc825b7c7, 0xaffb4363,
		0xf5df3999, 0x0fc688f1, 0xb07224cc, 0x03e86cea
	};

	private static final int[] RC00 = {
		0x303994a6, 0xc0e65299, 0x6cc33a12, 0xdc56983e,
		0x1e00108f, 0x7800423d, 0x8f5b7882, 0x96e1db12
	};

	private static final int[] RC04 = {
		0xe0337818, 0x441ba90d, 0x7f34d442, 0x9389217f,
		0xe5a8bce6, 0x5274baf4, 0x26889ba7, 0x9a226e9d
	};

	private static final int[] RC10 = {
		0xb6de10ed, 0x70f47aae, 0x0707a3d4, 0x1c1e8f51,
		0x707a3d45, 0xaeb28562, 0xbaca1589, 0x40a46f3e
	};

	private static final int[] RC14 = {
		0x01685f3d, 0x05a17cf4, 0xbd09caca, 0xf4272b28,
		0x144ae5cc, 0xfaa7ae2b, 0x2e48f1c1, 0xb923c704
	};

	private static final int[] RC20 = {
		0xfc20d9d2, 0x34552e25, 0x7ad8818f, 0x8438764a,
		0xbb6de032, 0xedb780c8, 0xd9847356, 0xa2c78434
	};

	private static final int[] RC24 = {
		0xe25e72c1, 0xe623bb72, 0x5c58a4a4, 0x1e38e2e7,
		0x78e38b9d, 0x27586719, 0x36eda57f, 0x703aace7
	};

	private static final int[] RC30 = {
		0xb213afa5, 0xc84ebe95, 0x4e608a22, 0x56d858fe,
		0x343b138f, 0xd0ec4e3d, 0x2ceb4882, 0xb3ad2208
	};

	private static final int[] RC34 = {
		0xe028c9bf, 0x44756f91, 0x7e8fce32, 0x956548be,
		0xfe191be2, 0x3cb226e5, 0x5944a28e, 0xa1c4c355
	};

	private static final int[] RC40 = {
		0xf0d2e9e3, 0xac11d7fa, 0x1bcb66f2, 0x6f2d9bc9,
		0x78602649, 0x8edae952, 0x3b6ba548, 0xedae9520
	};

	private static final int[] RC44 = {
		0x5090d577, 0x2d1925ab, 0xb46496ac, 0xd1925ab0,
		0x29131ab6, 0x0fc053c3, 0x3f014f0c, 0xfc053c31
	};

	private int V00, V01, V02, V03, V04, V05, V06, V07;
	private int V10, V11, V12, V13, V14, V15, V16, V17;
	private int V20, V21, V22, V23, V24, V25, V26, V27;
	private int V30, V31, V32, V33, V34, V35, V36, V37;
	private int V40, V41, V42, V43, V44, V45, V46, V47;
	private byte[] tmpBuf;

	/**
	 * Create the engine.
	 */
	public Luffa512()
	{
		super();
	}

	/** @see DigestEngine */
	public int getInternalBlockLength()
	{
		return 32;
	}

	/** @see Digest */
	public int getBlockLength()
	{
		/*
		 * Private communication for Luffa designer Watanabe Dai:
		 *
		 * << I think that there is no problem to use the same
		 *    setting as CubeHash, namely B = 256*ceil(k / 256). >>
		 */
		return -32;
	}

	/** @see Digest */
	public int getDigestLength()
	{
		return 64;
	}

	/** @see Digest */
	public Digest copy()
	{
		return copyState(new Luffa512());
	}

	/** @see DigestEngine */
	protected Digest copyState(Luffa512 dst)
	{
		dst.V00 = V00;
		dst.V01 = V01;
		dst.V02 = V02;
		dst.V03 = V03;
		dst.V04 = V04;
		dst.V05 = V05;
		dst.V06 = V06;
		dst.V07 = V07;
		dst.V10 = V10;
		dst.V11 = V11;
		dst.V12 = V12;
		dst.V13 = V13;
		dst.V14 = V14;
		dst.V15 = V15;
		dst.V16 = V16;
		dst.V17 = V17;
		dst.V20 = V20;
		dst.V21 = V21;
		dst.V22 = V22;
		dst.V23 = V23;
		dst.V24 = V24;
		dst.V25 = V25;
		dst.V26 = V26;
		dst.V27 = V27;
		dst.V30 = V30;
		dst.V31 = V31;
		dst.V32 = V32;
		dst.V33 = V33;
		dst.V34 = V34;
		dst.V35 = V35;
		dst.V36 = V36;
		dst.V37 = V37;
		dst.V40 = V40;
		dst.V41 = V41;
		dst.V42 = V42;
		dst.V43 = V43;
		dst.V44 = V44;
		dst.V45 = V45;
		dst.V46 = V46;
		dst.V47 = V47;
		return super.copyState(dst);
	}

	/** @see DigestEngine */
	protected void engineReset()
	{
		V00 = IV[ 0];
		V01 = IV[ 1];
		V02 = IV[ 2];
		V03 = IV[ 3];
		V04 = IV[ 4];
		V05 = IV[ 5];
		V06 = IV[ 6];
		V07 = IV[ 7];
		V10 = IV[ 8];
		V11 = IV[ 9];
		V12 = IV[10];
		V13 = IV[11];
		V14 = IV[12];
		V15 = IV[13];
		V16 = IV[14];
		V17 = IV[15];
		V20 = IV[16];
		V21 = IV[17];
		V22 = IV[18];
		V23 = IV[19];
		V24 = IV[20];
		V25 = IV[21];
		V26 = IV[22];
		V27 = IV[23];
		V30 = IV[24];
		V31 = IV[25];
		V32 = IV[26];
		V33 = IV[27];
		V34 = IV[28];
		V35 = IV[29];
		V36 = IV[30];
		V37 = IV[31];
		V40 = IV[32];
		V41 = IV[33];
		V42 = IV[34];
		V43 = IV[35];
		V44 = IV[36];
		V45 = IV[37];
		V46 = IV[38];
		V47 = IV[39];
	}

	/** @see DigestEngine */
	protected void doPadding(byte[] out, int off)
	{
		int ptr = flush();
		tmpBuf[ptr] = (byte)0x80;
		for (int i = ptr + 1; i < 32; i ++)
			tmpBuf[i] = 0x00;
		update(tmpBuf, ptr, 32 - ptr);
		for (int i = 0; i < ptr + 1; i ++)
			tmpBuf[i] = 0x00;
		update(tmpBuf, 0, 32);
		encodeBEInt(V00 ^ V10 ^ V20 ^ V30 ^ V40, out, off +  0);
		encodeBEInt(V01 ^ V11 ^ V21 ^ V31 ^ V41, out, off +  4);
		encodeBEInt(V02 ^ V12 ^ V22 ^ V32 ^ V42, out, off +  8);
		encodeBEInt(V03 ^ V13 ^ V23 ^ V33 ^ V43, out, off + 12);
		encodeBEInt(V04 ^ V14 ^ V24 ^ V34 ^ V44, out, off + 16);
		encodeBEInt(V05 ^ V15 ^ V25 ^ V35 ^ V45, out, off + 20);
		encodeBEInt(V06 ^ V16 ^ V26 ^ V36 ^ V46, out, off + 24);
		encodeBEInt(V07 ^ V17 ^ V27 ^ V37 ^ V47, out, off + 28);
		update(tmpBuf, 0, 32);
		encodeBEInt(V00 ^ V10 ^ V20 ^ V30 ^ V40, out, off + 32);
		encodeBEInt(V01 ^ V11 ^ V21 ^ V31 ^ V41, out, off + 36);
		encodeBEInt(V02 ^ V12 ^ V22 ^ V32 ^ V42, out, off + 40);
		encodeBEInt(V03 ^ V13 ^ V23 ^ V33 ^ V43, out, off + 44);
		encodeBEInt(V04 ^ V14 ^ V24 ^ V34 ^ V44, out, off + 48);
		encodeBEInt(V05 ^ V15 ^ V25 ^ V35 ^ V45, out, off + 52);
		encodeBEInt(V06 ^ V16 ^ V26 ^ V36 ^ V46, out, off + 56);
		encodeBEInt(V07 ^ V17 ^ V27 ^ V37 ^ V47, out, off + 60);
	}

	/** @see DigestEngine */
	protected void doInit()
	{
		tmpBuf = new byte[32];
		engineReset();
	}

	/**
	 * Encode the 32-bit word {@code val} into the array
	 * {@code buf} at offset {@code off}, in big-endian
	 * convention (most significant byte first).
	 *
	 * @param val   the value to encode
	 * @param buf   the destination buffer
	 * @param off   the destination offset
	 */
	private static final void encodeBEInt(int val, byte[] buf, int off)
	{
		buf[off + 0] = (byte)(val >>> 24);
		buf[off + 1] = (byte)(val >>> 16);
		buf[off + 2] = (byte)(val >>> 8);
		buf[off + 3] = (byte)val;
	}

	/**
	 * Decode a 32-bit big-endian word from the array {@code buf}
	 * at offset {@code off}.
	 *
	 * @param buf   the source buffer
	 * @param off   the source offset
	 * @return  the decoded value
	 */
	private static final int decodeBEInt(byte[] buf, int off)
	{
		return ((buf[off] & 0xFF) << 24)
			| ((buf[off + 1] & 0xFF) << 16)
			| ((buf[off + 2] & 0xFF) << 8)
			| (buf[off + 3] & 0xFF);
	}

	/** @see DigestEngine */
	protected void processBlock(byte[] data)
	{
		int tmp;
		int a0, a1, a2, a3, a4, a5, a6, a7;
		int b0, b1, b2, b3, b4, b5, b6, b7;
		int M0 = decodeBEInt(data, 0);
		int M1 = decodeBEInt(data, 4);
		int M2 = decodeBEInt(data, 8);
		int M3 = decodeBEInt(data, 12);
		int M4 = decodeBEInt(data, 16);
		int M5 = decodeBEInt(data, 20);
		int M6 = decodeBEInt(data, 24);
		int M7 = decodeBEInt(data, 28);
		a0 = V00 ^ V10;
		a1 = V01 ^ V11;
		a2 = V02 ^ V12;
		a3 = V03 ^ V13;
		a4 = V04 ^ V14;
		a5 = V05 ^ V15;
		a6 = V06 ^ V16;
		a7 = V07 ^ V17;
		b0 = V20 ^ V30;
		b1 = V21 ^ V31;
		b2 = V22 ^ V32;
		b3 = V23 ^ V33;
		b4 = V24 ^ V34;
		b5 = V25 ^ V35;
		b6 = V26 ^ V36;
		b7 = V27 ^ V37;
		a0 = a0 ^ b0;
		a1 = a1 ^ b1;
		a2 = a2 ^ b2;
		a3 = a3 ^ b3;
		a4 = a4 ^ b4;
		a5 = a5 ^ b5;
		a6 = a6 ^ b6;
		a7 = a7 ^ b7;
		a0 = a0 ^ V40;
		a1 = a1 ^ V41;
		a2 = a2 ^ V42;
		a3 = a3 ^ V43;
		a4 = a4 ^ V44;
		a5 = a5 ^ V45;
		a6 = a6 ^ V46;
		a7 = a7 ^ V47;
		tmp = a7;
		a7 = a6;
		a6 = a5;
		a5 = a4;
		a4 = a3 ^ tmp;
		a3 = a2 ^ tmp;
		a2 = a1;
		a1 = a0 ^ tmp;
		a0 = tmp;
		V00 = a0 ^ V00;
		V01 = a1 ^ V01;
		V02 = a2 ^ V02;
		V03 = a3 ^ V03;
		V04 = a4 ^ V04;
		V05 = a5 ^ V05;
		V06 = a6 ^ V06;
		V07 = a7 ^ V07;
		V10 = a0 ^ V10;
		V11 = a1 ^ V11;
		V12 = a2 ^ V12;
		V13 = a3 ^ V13;
		V14 = a4 ^ V14;
		V15 = a5 ^ V15;
		V16 = a6 ^ V16;
		V17 = a7 ^ V17;
		V20 = a0 ^ V20;
		V21 = a1 ^ V21;
		V22 = a2 ^ V22;
		V23 = a3 ^ V23;
		V24 = a4 ^ V24;
		V25 = a5 ^ V25;
		V26 = a6 ^ V26;
		V27 = a7 ^ V27;
		V30 = a0 ^ V30;
		V31 = a1 ^ V31;
		V32 = a2 ^ V32;
		V33 = a3 ^ V33;
		V34 = a4 ^ V34;
		V35 = a5 ^ V35;
		V36 = a6 ^ V36;
		V37 = a7 ^ V37;
		V40 = a0 ^ V40;
		V41 = a1 ^ V41;
		V42 = a2 ^ V42;
		V43 = a3 ^ V43;
		V44 = a4 ^ V44;
		V45 = a5 ^ V45;
		V46 = a6 ^ V46;
		V47 = a7 ^ V47;
		tmp = V07;
		b7 = V06;
		b6 = V05;
		b5 = V04;
		b4 = V03 ^ tmp;
		b3 = V02 ^ tmp;
		b2 = V01;
		b1 = V00 ^ tmp;
		b0 = tmp;
		b0 = b0 ^ V10;
		b1 = b1 ^ V11;
		b2 = b2 ^ V12;
		b3 = b3 ^ V13;
		b4 = b4 ^ V14;
		b5 = b5 ^ V15;
		b6 = b6 ^ V16;
		b7 = b7 ^ V17;
		tmp = V17;
		V17 = V16;
		V16 = V15;
		V15 = V14;
		V14 = V13 ^ tmp;
		V13 = V12 ^ tmp;
		V12 = V11;
		V11 = V10 ^ tmp;
		V10 = tmp;
		V10 = V10 ^ V20;
		V11 = V11 ^ V21;
		V12 = V12 ^ V22;
		V13 = V13 ^ V23;
		V14 = V14 ^ V24;
		V15 = V15 ^ V25;
		V16 = V16 ^ V26;
		V17 = V17 ^ V27;
		tmp = V27;
		V27 = V26;
		V26 = V25;
		V25 = V24;
		V24 = V23 ^ tmp;
		V23 = V22 ^ tmp;
		V22 = V21;
		V21 = V20 ^ tmp;
		V20 = tmp;
		V20 = V20 ^ V30;
		V21 = V21 ^ V31;
		V22 = V22 ^ V32;
		V23 = V23 ^ V33;
		V24 = V24 ^ V34;
		V25 = V25 ^ V35;
		V26 = V26 ^ V36;
		V27 = V27 ^ V37;
		tmp = V37;
		V37 = V36;
		V36 = V35;
		V35 = V34;
		V34 = V33 ^ tmp;
		V33 = V32 ^ tmp;
		V32 = V31;
		V31 = V30 ^ tmp;
		V30 = tmp;
		V30 = V30 ^ V40;
		V31 = V31 ^ V41;
		V32 = V32 ^ V42;
		V33 = V33 ^ V43;
		V34 = V34 ^ V44;
		V35 = V35 ^ V45;
		V36 = V36 ^ V46;
		V37 = V37 ^ V47;
		tmp = V47;
		V47 = V46;
		V46 = V45;
		V45 = V44;
		V44 = V43 ^ tmp;
		V43 = V42 ^ tmp;
		V42 = V41;
		V41 = V40 ^ tmp;
		V40 = tmp;
		V40 = V40 ^ V00;
		V41 = V41 ^ V01;
		V42 = V42 ^ V02;
		V43 = V43 ^ V03;
		V44 = V44 ^ V04;
		V45 = V45 ^ V05;
		V46 = V46 ^ V06;
		V47 = V47 ^ V07;
		tmp = b7;
		V07 = b6;
		V06 = b5;
		V05 = b4;
		V04 = b3 ^ tmp;
		V03 = b2 ^ tmp;
		V02 = b1;
		V01 = b0 ^ tmp;
		V00 = tmp;
		V00 = V00 ^ V40;
		V01 = V01 ^ V41;
		V02 = V02 ^ V42;
		V03 = V03 ^ V43;
		V04 = V04 ^ V44;
		V05 = V05 ^ V45;
		V06 = V06 ^ V46;
		V07 = V07 ^ V47;
		tmp = V47;
		V47 = V46;
		V46 = V45;
		V45 = V44;
		V44 = V43 ^ tmp;
		V43 = V42 ^ tmp;
		V42 = V41;
		V41 = V40 ^ tmp;
		V40 = tmp;
		V40 = V40 ^ V30;
		V41 = V41 ^ V31;
		V42 = V42 ^ V32;
		V43 = V43 ^ V33;
		V44 = V44 ^ V34;
		V45 = V45 ^ V35;
		V46 = V46 ^ V36;
		V47 = V47 ^ V37;
		tmp = V37;
		V37 = V36;
		V36 = V35;
		V35 = V34;
		V34 = V33 ^ tmp;
		V33 = V32 ^ tmp;
		V32 = V31;
		V31 = V30 ^ tmp;
		V30 = tmp;
		V30 = V30 ^ V20;
		V31 = V31 ^ V21;
		V32 = V32 ^ V22;
		V33 = V33 ^ V23;
		V34 = V34 ^ V24;
		V35 = V35 ^ V25;
		V36 = V36 ^ V26;
		V37 = V37 ^ V27;
		tmp = V27;
		V27 = V26;
		V26 = V25;
		V25 = V24;
		V24 = V23 ^ tmp;
		V23 = V22 ^ tmp;
		V22 = V21;
		V21 = V20 ^ tmp;
		V20 = tmp;
		V20 = V20 ^ V10;
		V21 = V21 ^ V11;
		V22 = V22 ^ V12;
		V23 = V23 ^ V13;
		V24 = V24 ^ V14;
		V25 = V25 ^ V15;
		V26 = V26 ^ V16;
		V27 = V27 ^ V17;
		tmp = V17;
		V17 = V16;
		V16 = V15;
		V15 = V14;
		V14 = V13 ^ tmp;
		V13 = V12 ^ tmp;
		V12 = V11;
		V11 = V10 ^ tmp;
		V10 = tmp;
		V10 = V10 ^ b0;
		V11 = V11 ^ b1;
		V12 = V12 ^ b2;
		V13 = V13 ^ b3;
		V14 = V14 ^ b4;
		V15 = V15 ^ b5;
		V16 = V16 ^ b6;
		V17 = V17 ^ b7;
		V00 = V00 ^ M0;
		V01 = V01 ^ M1;
		V02 = V02 ^ M2;
		V03 = V03 ^ M3;
		V04 = V04 ^ M4;
		V05 = V05 ^ M5;
		V06 = V06 ^ M6;
		V07 = V07 ^ M7;
		tmp = M7;
		M7 = M6;
		M6 = M5;
		M5 = M4;
		M4 = M3 ^ tmp;
		M3 = M2 ^ tmp;
		M2 = M1;
		M1 = M0 ^ tmp;
		M0 = tmp;
		V10 = V10 ^ M0;
		V11 = V11 ^ M1;
		V12 = V12 ^ M2;
		V13 = V13 ^ M3;
		V14 = V14 ^ M4;
		V15 = V15 ^ M5;
		V16 = V16 ^ M6;
		V17 = V17 ^ M7;
		tmp = M7;
		M7 = M6;
		M6 = M5;
		M5 = M4;
		M4 = M3 ^ tmp;
		M3 = M2 ^ tmp;
		M2 = M1;
		M1 = M0 ^ tmp;
		M0 = tmp;
		V20 = V20 ^ M0;
		V21 = V21 ^ M1;
		V22 = V22 ^ M2;
		V23 = V23 ^ M3;
		V24 = V24 ^ M4;
		V25 = V25 ^ M5;
		V26 = V26 ^ M6;
		V27 = V27 ^ M7;
		tmp = M7;
		M7 = M6;
		M6 = M5;
		M5 = M4;
		M4 = M3 ^ tmp;
		M3 = M2 ^ tmp;
		M2 = M1;
		M1 = M0 ^ tmp;
		M0 = tmp;
		V30 = V30 ^ M0;
		V31 = V31 ^ M1;
		V32 = V32 ^ M2;
		V33 = V33 ^ M3;
		V34 = V34 ^ M4;
		V35 = V35 ^ M5;
		V36 = V36 ^ M6;
		V37 = V37 ^ M7;
		tmp = M7;
		M7 = M6;
		M6 = M5;
		M5 = M4;
		M4 = M3 ^ tmp;
		M3 = M2 ^ tmp;
		M2 = M1;
		M1 = M0 ^ tmp;
		M0 = tmp;
		V40 = V40 ^ M0;
		V41 = V41 ^ M1;
		V42 = V42 ^ M2;
		V43 = V43 ^ M3;
		V44 = V44 ^ M4;
		V45 = V45 ^ M5;
		V46 = V46 ^ M6;
		V47 = V47 ^ M7;
		V14 = (V14 << 1) | (V14 >>> 31);
		V15 = (V15 << 1) | (V15 >>> 31);
		V16 = (V16 << 1) | (V16 >>> 31);
		V17 = (V17 << 1) | (V17 >>> 31);
		V24 = (V24 << 2) | (V24 >>> 30);
		V25 = (V25 << 2) | (V25 >>> 30);
		V26 = (V26 << 2) | (V26 >>> 30);
		V27 = (V27 << 2) | (V27 >>> 30);
		V34 = (V34 << 3) | (V34 >>> 29);
		V35 = (V35 << 3) | (V35 >>> 29);
		V36 = (V36 << 3) | (V36 >>> 29);
		V37 = (V37 << 3) | (V37 >>> 29);
		V44 = (V44 << 4) | (V44 >>> 28);
		V45 = (V45 << 4) | (V45 >>> 28);
		V46 = (V46 << 4) | (V46 >>> 28);
		V47 = (V47 << 4) | (V47 >>> 28);
		for (int r = 0; r < 8; r++) {
			tmp = V00;
			V00 |= V01;
			V02 ^= V03;
			V01 = ~V01;
			V00 ^= V03;
			V03 &= tmp;
			V01 ^= V03;
			V03 ^= V02;
			V02 &= V00;
			V00 = ~V00;
			V02 ^= V01;
			V01 |= V03;
			tmp ^= V01;
			V03 ^= V02;
			V02 &= V01;
			V01 ^= V00;
			V00 = tmp;
			tmp = V05;
			V05 |= V06;
			V07 ^= V04;
			V06 = ~V06;
			V05 ^= V04;
			V04 &= tmp;
			V06 ^= V04;
			V04 ^= V07;
			V07 &= V05;
			V05 = ~V05;
			V07 ^= V06;
			V06 |= V04;
			tmp ^= V06;
			V04 ^= V07;
			V07 &= V06;
			V06 ^= V05;
			V05 = tmp;
			V04 ^= V00;
			V00 = ((V00 << 2) | (V00 >>> 30)) ^ V04;
			V04 = ((V04 << 14) | (V04 >>> 18)) ^ V00;
			V00 = ((V00 << 10) | (V00 >>> 22)) ^ V04;
			V04 = (V04 << 1) | (V04 >>> 31);
			V05 ^= V01;
			V01 = ((V01 << 2) | (V01 >>> 30)) ^ V05;
			V05 = ((V05 << 14) | (V05 >>> 18)) ^ V01;
			V01 = ((V01 << 10) | (V01 >>> 22)) ^ V05;
			V05 = (V05 << 1) | (V05 >>> 31);
			V06 ^= V02;
			V02 = ((V02 << 2) | (V02 >>> 30)) ^ V06;
			V06 = ((V06 << 14) | (V06 >>> 18)) ^ V02;
			V02 = ((V02 << 10) | (V02 >>> 22)) ^ V06;
			V06 = (V06 << 1) | (V06 >>> 31);
			V07 ^= V03;
			V03 = ((V03 << 2) | (V03 >>> 30)) ^ V07;
			V07 = ((V07 << 14) | (V07 >>> 18)) ^ V03;
			V03 = ((V03 << 10) | (V03 >>> 22)) ^ V07;
			V07 = (V07 << 1) | (V07 >>> 31);
			V00 ^= RC00[r];
			V04 ^= RC04[r];
		}
		for (int r = 0; r < 8; r++) {
			tmp = V10;
			V10 |= V11;
			V12 ^= V13;
			V11 = ~V11;
			V10 ^= V13;
			V13 &= tmp;
			V11 ^= V13;
			V13 ^= V12;
			V12 &= V10;
			V10 = ~V10;
			V12 ^= V11;
			V11 |= V13;
			tmp ^= V11;
			V13 ^= V12;
			V12 &= V11;
			V11 ^= V10;
			V10 = tmp;
			tmp = V15;
			V15 |= V16;
			V17 ^= V14;
			V16 = ~V16;
			V15 ^= V14;
			V14 &= tmp;
			V16 ^= V14;
			V14 ^= V17;
			V17 &= V15;
			V15 = ~V15;
			V17 ^= V16;
			V16 |= V14;
			tmp ^= V16;
			V14 ^= V17;
			V17 &= V16;
			V16 ^= V15;
			V15 = tmp;
			V14 ^= V10;
			V10 = ((V10 << 2) | (V10 >>> 30)) ^ V14;
			V14 = ((V14 << 14) | (V14 >>> 18)) ^ V10;
			V10 = ((V10 << 10) | (V10 >>> 22)) ^ V14;
			V14 = (V14 << 1) | (V14 >>> 31);
			V15 ^= V11;
			V11 = ((V11 << 2) | (V11 >>> 30)) ^ V15;
			V15 = ((V15 << 14) | (V15 >>> 18)) ^ V11;
			V11 = ((V11 << 10) | (V11 >>> 22)) ^ V15;
			V15 = (V15 << 1) | (V15 >>> 31);
			V16 ^= V12;
			V12 = ((V12 << 2) | (V12 >>> 30)) ^ V16;
			V16 = ((V16 << 14) | (V16 >>> 18)) ^ V12;
			V12 = ((V12 << 10) | (V12 >>> 22)) ^ V16;
			V16 = (V16 << 1) | (V16 >>> 31);
			V17 ^= V13;
			V13 = ((V13 << 2) | (V13 >>> 30)) ^ V17;
			V17 = ((V17 << 14) | (V17 >>> 18)) ^ V13;
			V13 = ((V13 << 10) | (V13 >>> 22)) ^ V17;
			V17 = (V17 << 1) | (V17 >>> 31);
			V10 ^= RC10[r];
			V14 ^= RC14[r];
		}
		for (int r = 0; r < 8; r++) {
			tmp = V20;
			V20 |= V21;
			V22 ^= V23;
			V21 = ~V21;
			V20 ^= V23;
			V23 &= tmp;
			V21 ^= V23;
			V23 ^= V22;
			V22 &= V20;
			V20 = ~V20;
			V22 ^= V21;
			V21 |= V23;
			tmp ^= V21;
			V23 ^= V22;
			V22 &= V21;
			V21 ^= V20;
			V20 = tmp;
			tmp = V25;
			V25 |= V26;
			V27 ^= V24;
			V26 = ~V26;
			V25 ^= V24;
			V24 &= tmp;
			V26 ^= V24;
			V24 ^= V27;
			V27 &= V25;
			V25 = ~V25;
			V27 ^= V26;
			V26 |= V24;
			tmp ^= V26;
			V24 ^= V27;
			V27 &= V26;
			V26 ^= V25;
			V25 = tmp;
			V24 ^= V20;
			V20 = ((V20 << 2) | (V20 >>> 30)) ^ V24;
			V24 = ((V24 << 14) | (V24 >>> 18)) ^ V20;
			V20 = ((V20 << 10) | (V20 >>> 22)) ^ V24;
			V24 = (V24 << 1) | (V24 >>> 31);
			V25 ^= V21;
			V21 = ((V21 << 2) | (V21 >>> 30)) ^ V25;
			V25 = ((V25 << 14) | (V25 >>> 18)) ^ V21;
			V21 = ((V21 << 10) | (V21 >>> 22)) ^ V25;
			V25 = (V25 << 1) | (V25 >>> 31);
			V26 ^= V22;
			V22 = ((V22 << 2) | (V22 >>> 30)) ^ V26;
			V26 = ((V26 << 14) | (V26 >>> 18)) ^ V22;
			V22 = ((V22 << 10) | (V22 >>> 22)) ^ V26;
			V26 = (V26 << 1) | (V26 >>> 31);
			V27 ^= V23;
			V23 = ((V23 << 2) | (V23 >>> 30)) ^ V27;
			V27 = ((V27 << 14) | (V27 >>> 18)) ^ V23;
			V23 = ((V23 << 10) | (V23 >>> 22)) ^ V27;
			V27 = (V27 << 1) | (V27 >>> 31);
			V20 ^= RC20[r];
			V24 ^= RC24[r];
		}
		for (int r = 0; r < 8; r++) {
			tmp = V30;
			V30 |= V31;
			V32 ^= V33;
			V31 = ~V31;
			V30 ^= V33;
			V33 &= tmp;
			V31 ^= V33;
			V33 ^= V32;
			V32 &= V30;
			V30 = ~V30;
			V32 ^= V31;
			V31 |= V33;
			tmp ^= V31;
			V33 ^= V32;
			V32 &= V31;
			V31 ^= V30;
			V30 = tmp;
			tmp = V35;
			V35 |= V36;
			V37 ^= V34;
			V36 = ~V36;
			V35 ^= V34;
			V34 &= tmp;
			V36 ^= V34;
			V34 ^= V37;
			V37 &= V35;
			V35 = ~V35;
			V37 ^= V36;
			V36 |= V34;
			tmp ^= V36;
			V34 ^= V37;
			V37 &= V36;
			V36 ^= V35;
			V35 = tmp;
			V34 ^= V30;
			V30 = ((V30 << 2) | (V30 >>> 30)) ^ V34;
			V34 = ((V34 << 14) | (V34 >>> 18)) ^ V30;
			V30 = ((V30 << 10) | (V30 >>> 22)) ^ V34;
			V34 = (V34 << 1) | (V34 >>> 31);
			V35 ^= V31;
			V31 = ((V31 << 2) | (V31 >>> 30)) ^ V35;
			V35 = ((V35 << 14) | (V35 >>> 18)) ^ V31;
			V31 = ((V31 << 10) | (V31 >>> 22)) ^ V35;
			V35 = (V35 << 1) | (V35 >>> 31);
			V36 ^= V32;
			V32 = ((V32 << 2) | (V32 >>> 30)) ^ V36;
			V36 = ((V36 << 14) | (V36 >>> 18)) ^ V32;
			V32 = ((V32 << 10) | (V32 >>> 22)) ^ V36;
			V36 = (V36 << 1) | (V36 >>> 31);
			V37 ^= V33;
			V33 = ((V33 << 2) | (V33 >>> 30)) ^ V37;
			V37 = ((V37 << 14) | (V37 >>> 18)) ^ V33;
			V33 = ((V33 << 10) | (V33 >>> 22)) ^ V37;
			V37 = (V37 << 1) | (V37 >>> 31);
			V30 ^= RC30[r];
			V34 ^= RC34[r];
		}
		for (int r = 0; r < 8; r++) {
			tmp = V40;
			V40 |= V41;
			V42 ^= V43;
			V41 = ~V41;
			V40 ^= V43;
			V43 &= tmp;
			V41 ^= V43;
			V43 ^= V42;
			V42 &= V40;
			V40 = ~V40;
			V42 ^= V41;
			V41 |= V43;
			tmp ^= V41;
			V43 ^= V42;
			V42 &= V41;
			V41 ^= V40;
			V40 = tmp;
			tmp = V45;
			V45 |= V46;
			V47 ^= V44;
			V46 = ~V46;
			V45 ^= V44;
			V44 &= tmp;
			V46 ^= V44;
			V44 ^= V47;
			V47 &= V45;
			V45 = ~V45;
			V47 ^= V46;
			V46 |= V44;
			tmp ^= V46;
			V44 ^= V47;
			V47 &= V46;
			V46 ^= V45;
			V45 = tmp;
			V44 ^= V40;
			V40 = ((V40 << 2) | (V40 >>> 30)) ^ V44;
			V44 = ((V44 << 14) | (V44 >>> 18)) ^ V40;
			V40 = ((V40 << 10) | (V40 >>> 22)) ^ V44;
			V44 = (V44 << 1) | (V44 >>> 31);
			V45 ^= V41;
			V41 = ((V41 << 2) | (V41 >>> 30)) ^ V45;
			V45 = ((V45 << 14) | (V45 >>> 18)) ^ V41;
			V41 = ((V41 << 10) | (V41 >>> 22)) ^ V45;
			V45 = (V45 << 1) | (V45 >>> 31);
			V46 ^= V42;
			V42 = ((V42 << 2) | (V42 >>> 30)) ^ V46;
			V46 = ((V46 << 14) | (V46 >>> 18)) ^ V42;
			V42 = ((V42 << 10) | (V42 >>> 22)) ^ V46;
			V46 = (V46 << 1) | (V46 >>> 31);
			V47 ^= V43;
			V43 = ((V43 << 2) | (V43 >>> 30)) ^ V47;
			V47 = ((V47 << 14) | (V47 >>> 18)) ^ V43;
			V43 = ((V43 << 10) | (V43 >>> 22)) ^ V47;
			V47 = (V47 << 1) | (V47 >>> 31);
			V40 ^= RC40[r];
			V44 ^= RC44[r];
		}
	}

	/** @see Digest */
	public String toString()
	{
		return "Luffa-512";
	}
}