// $Id: PANAMA.java 54 2007-01-24 16:22:09Z tp $ package fr.cryptohash; /** * This class implements the PANAMA digest algorithm under the * <code>Digest</code> API. * * <pre> * ==========================(LICENSE BEGIN)============================ * * Copyright (c) 2007 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: 54 $ * @author Thomas Pornin <thomas.pornin@cryptolog.com> */ public class PANAMA extends DigestEngine { /** * Create the object. */ public PANAMA() { } private int[] buffer; private int bufferPtr; private int state0, state1, state2, state3, state4, state5; private int state6, state7, state8, state9, state10, state11; private int state12, state13, state14, state15, state16; private int inData0, inData1, inData2, inData3; private int inData4, inData5, inData6, inData7; /** @see Digest */ public Digest copy() { PANAMA d = new PANAMA(); System.arraycopy(buffer, 0, d.buffer, 0, buffer.length); d.bufferPtr = bufferPtr; d.state0 = state0 ; d.state1 = state1 ; d.state2 = state2 ; d.state3 = state3 ; d.state4 = state4 ; d.state5 = state5 ; d.state6 = state6 ; d.state7 = state7 ; d.state8 = state8 ; d.state9 = state9 ; d.state10 = state10; d.state11 = state11; d.state12 = state12; d.state13 = state13; d.state14 = state14; d.state15 = state15; d.state16 = state16; return copyState(d); } /** @see Digest */ public int getDigestLength() { return 32; } /** @see Digest */ public int getBlockLength() { return 32; } /** @see DigestEngine */ protected void engineReset() { for (int i = 0; i < buffer.length; i ++) buffer[i] = 0; bufferPtr = 0; state0 = 0; state1 = 0; state2 = 0; state3 = 0; state4 = 0; state5 = 0; state6 = 0; state7 = 0; state8 = 0; state9 = 0; state10 = 0; state11 = 0; state12 = 0; state13 = 0; state14 = 0; state15 = 0; state16 = 0; } /** @see DigestEngine */ protected void doPadding(byte[] output, int outputOffset) { int pending = flush(); update((byte)0x01); for (int i = pending + 1; i < 32; i ++) update((byte)0x00); flush(); for (int i = 0; i < 32; i ++) oneStep(false); encodeLEInt(state9, output, outputOffset + 0); encodeLEInt(state10, output, outputOffset + 4); encodeLEInt(state11, output, outputOffset + 8); encodeLEInt(state12, output, outputOffset + 12); encodeLEInt(state13, output, outputOffset + 16); encodeLEInt(state14, output, outputOffset + 20); encodeLEInt(state15, output, outputOffset + 24); encodeLEInt(state16, output, outputOffset + 28); } /** @see DigestEngine */ protected void doInit() { buffer = new int[256]; /* * engineReset() is not needed because in Java, "int" * variables and arrays of "int" are initialized upon * creation to the correct value (full of zeroes). */ } /** * Encode the 32-bit word <code>val</code> into the array * <code>buf</code> at offset <code>off</code>, in little-endian * convention (least significant byte first). * * @param val the value to encode * @param buf the destination buffer * @param off the destination offset */ static private final void encodeLEInt(int val, byte[] buf, int off) { buf[off + 3] = (byte)((val >> 24) & 0xff); buf[off + 2] = (byte)((val >> 16) & 0xff); buf[off + 1] = (byte)((val >> 8) & 0xff); buf[off + 0] = (byte)(val & 0xff); } /** * Decode a 32-bit little-endian word from the array <code>buf</code> * at offset <code>off</code>. * * @param buf the source buffer * @param off the source offset * @return the decoded value */ static private final int decodeLEInt(byte[] buf, int off) { return (buf[off] & 0xFF) | ((buf[off + 1] & 0xFF) << 8) | ((buf[off + 2] & 0xFF) << 16) | ((buf[off + 3] & 0xFF) << 24); } /** @see DigestEngine */ protected void processBlock(byte[] data) { inData0 = decodeLEInt(data, 0); inData1 = decodeLEInt(data, 4); inData2 = decodeLEInt(data, 8); inData3 = decodeLEInt(data, 12); inData4 = decodeLEInt(data, 16); inData5 = decodeLEInt(data, 20); inData6 = decodeLEInt(data, 24); inData7 = decodeLEInt(data, 28); oneStep(true); } private final void oneStep(boolean push) { /* * Buffer update. */ int ptr0 = bufferPtr; int ptr24 = (ptr0 - 64) & 248; int ptr31 = (ptr0 - 8) & 248; if (push) { buffer[ptr24 + 0] ^= buffer[ptr31 + 2]; buffer[ptr31 + 2] ^= inData2; buffer[ptr24 + 1] ^= buffer[ptr31 + 3]; buffer[ptr31 + 3] ^= inData3; buffer[ptr24 + 2] ^= buffer[ptr31 + 4]; buffer[ptr31 + 4] ^= inData4; buffer[ptr24 + 3] ^= buffer[ptr31 + 5]; buffer[ptr31 + 5] ^= inData5; buffer[ptr24 + 4] ^= buffer[ptr31 + 6]; buffer[ptr31 + 6] ^= inData6; buffer[ptr24 + 5] ^= buffer[ptr31 + 7]; buffer[ptr31 + 7] ^= inData7; buffer[ptr24 + 6] ^= buffer[ptr31 + 0]; buffer[ptr31 + 0] ^= inData0; buffer[ptr24 + 7] ^= buffer[ptr31 + 1]; buffer[ptr31 + 1] ^= inData1; } else { buffer[ptr24 + 0] ^= buffer[ptr31 + 2]; buffer[ptr31 + 2] ^= state3; buffer[ptr24 + 1] ^= buffer[ptr31 + 3]; buffer[ptr31 + 3] ^= state4; buffer[ptr24 + 2] ^= buffer[ptr31 + 4]; buffer[ptr31 + 4] ^= state5; buffer[ptr24 + 3] ^= buffer[ptr31 + 5]; buffer[ptr31 + 5] ^= state6; buffer[ptr24 + 4] ^= buffer[ptr31 + 6]; buffer[ptr31 + 6] ^= state7; buffer[ptr24 + 5] ^= buffer[ptr31 + 7]; buffer[ptr31 + 7] ^= state8; buffer[ptr24 + 6] ^= buffer[ptr31 + 0]; buffer[ptr31 + 0] ^= state1; buffer[ptr24 + 7] ^= buffer[ptr31 + 1]; buffer[ptr31 + 1] ^= state2; } bufferPtr = ptr31; /* * Gamma transform. */ int g0, g1, g2, g3, g4, g5, g6, g7, g8, g9; int g10, g11, g12, g13, g14, g15, g16; g0 = state0 ^ (state1 | ~state2 ); g1 = state1 ^ (state2 | ~state3 ); g2 = state2 ^ (state3 | ~state4 ); g3 = state3 ^ (state4 | ~state5 ); g4 = state4 ^ (state5 | ~state6 ); g5 = state5 ^ (state6 | ~state7 ); g6 = state6 ^ (state7 | ~state8 ); g7 = state7 ^ (state8 | ~state9 ); g8 = state8 ^ (state9 | ~state10); g9 = state9 ^ (state10 | ~state11); g10 = state10 ^ (state11 | ~state12); g11 = state11 ^ (state12 | ~state13); g12 = state12 ^ (state13 | ~state14); g13 = state13 ^ (state14 | ~state15); g14 = state14 ^ (state15 | ~state16); g15 = state15 ^ (state16 | ~state0 ); g16 = state16 ^ (state0 | ~state1 ); /* * Pi transform. */ int p0, p1, p2, p3, p4, p5, p6, p7, p8, p9; int p10, p11, p12, p13, p14, p15, p16; p0 = g0; p1 = ( g7 << 1) | ( g7 >>> (32 - 1)); p2 = (g14 << 3) | (g14 >>> (32 - 3)); p3 = ( g4 << 6) | ( g4 >>> (32 - 6)); p4 = (g11 << 10) | (g11 >>> (32 - 10)); p5 = ( g1 << 15) | ( g1 >>> (32 - 15)); p6 = ( g8 << 21) | ( g8 >>> (32 - 21)); p7 = (g15 << 28) | (g15 >>> (32 - 28)); p8 = ( g5 << 4) | ( g5 >>> (32 - 4)); p9 = (g12 << 13) | (g12 >>> (32 - 13)); p10 = ( g2 << 23) | ( g2 >>> (32 - 23)); p11 = ( g9 << 2) | ( g9 >>> (32 - 2)); p12 = (g16 << 14) | (g16 >>> (32 - 14)); p13 = ( g6 << 27) | ( g6 >>> (32 - 27)); p14 = (g13 << 9) | (g13 >>> (32 - 9)); p15 = ( g3 << 24) | ( g3 >>> (32 - 24)); p16 = (g10 << 8) | (g10 >>> (32 - 8)); /* * Theta transform. */ int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; int t10, t11, t12, t13, t14, t15, t16; t0 = p0 ^ p1 ^ p4 ; t1 = p1 ^ p2 ^ p5 ; t2 = p2 ^ p3 ^ p6 ; t3 = p3 ^ p4 ^ p7 ; t4 = p4 ^ p5 ^ p8 ; t5 = p5 ^ p6 ^ p9 ; t6 = p6 ^ p7 ^ p10; t7 = p7 ^ p8 ^ p11; t8 = p8 ^ p9 ^ p12; t9 = p9 ^ p10 ^ p13; t10 = p10 ^ p11 ^ p14; t11 = p11 ^ p12 ^ p15; t12 = p12 ^ p13 ^ p16; t13 = p13 ^ p14 ^ p0 ; t14 = p14 ^ p15 ^ p1 ; t15 = p15 ^ p16 ^ p2 ; t16 = p16 ^ p0 ^ p3 ; /* * Sigma transform. */ int ptr16 = ptr0 ^ 128; state0 = t0 ^ 1; if (push) { state1 = t1 ^ inData0; state2 = t2 ^ inData1; state3 = t3 ^ inData2; state4 = t4 ^ inData3; state5 = t5 ^ inData4; state6 = t6 ^ inData5; state7 = t7 ^ inData6; state8 = t8 ^ inData7; } else { int ptr4 = (ptr0 + 32) & 248; state1 = t1 ^ buffer[ptr4 + 0]; state2 = t2 ^ buffer[ptr4 + 1]; state3 = t3 ^ buffer[ptr4 + 2]; state4 = t4 ^ buffer[ptr4 + 3]; state5 = t5 ^ buffer[ptr4 + 4]; state6 = t6 ^ buffer[ptr4 + 5]; state7 = t7 ^ buffer[ptr4 + 6]; state8 = t8 ^ buffer[ptr4 + 7]; } state9 = t9 ^ buffer[ptr16 + 0]; state10 = t10 ^ buffer[ptr16 + 1]; state11 = t11 ^ buffer[ptr16 + 2]; state12 = t12 ^ buffer[ptr16 + 3]; state13 = t13 ^ buffer[ptr16 + 4]; state14 = t14 ^ buffer[ptr16 + 5]; state15 = t15 ^ buffer[ptr16 + 6]; state16 = t16 ^ buffer[ptr16 + 7]; } }