package org.bouncycastle.crypto.test;

import java.security.SecureRandom;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.engines.ARIAEngine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;

public class ARIATest
    extends SimpleTest
{
    private static SecureRandom R = new SecureRandom();

    private static final String[][] TEST_VECTORS_RFC5794 = {
        {
            "128-Bit Key",
            "000102030405060708090a0b0c0d0e0f",
            "00112233445566778899aabbccddeeff",
            "d718fbd6ab644c739da95f3be6451778"
        },
        {
            "192-Bit Key",
            "000102030405060708090a0b0c0d0e0f1011121314151617",
            "00112233445566778899aabbccddeeff",
            "26449c1805dbe7aa25a468ce263a9e79"
        },
        {
            "256-Bit Key",
            "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
            "00112233445566778899aabbccddeeff",
            "f92bd7c79fb72e2f2b8f80c1972d24fc"
        },
    };

    public String getName()
    {
        return "ARIA";
    }

    public void performTest() throws Exception
    {
        checkTestVectors_RFC5794();
        long before = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
        {
        checkRandomRoundtrips();
        }
        long after = System.currentTimeMillis();
        long elapsed = after - before;
        System.out.println("Elapsed: " + elapsed + "ms.");

        new MyARIAEngine().checkImplementation();
    }

    private void checkRandomRoundtrips()
    {
        ARIAEngine ce = new ARIAEngine();
        ARIAEngine cd = new ARIAEngine();

        byte[] txt = new byte[ce.getBlockSize()];
        byte[] enc = new byte[ce.getBlockSize()];
        byte[] dec = new byte[ce.getBlockSize()];

        for (int keyLen = 16; keyLen <= 32; keyLen += 8)
        {
            byte[] K = new byte[keyLen];

            R.nextBytes(K);

            KeyParameter key = new KeyParameter(K);
            ce.init(true, key);
            cd.init(false, key);

            R.nextBytes(txt);

            for (int i = 0; i < 100; ++i)
            {
                ce.processBlock(txt, 0, enc, 0);
                cd.processBlock(enc, 0, dec, 0);

                isTrue(Arrays.areEqual(txt, dec));

                System.arraycopy(enc, 0, txt, 0, enc.length);
            }
        }
    }

    private void checkTestVector_RFC5794(String[] tv)
    {
        String name = "'" + tv[0] + "'";

        BlockCipher c = new ARIAEngine();
        int blockSize = c.getBlockSize();
        isTrue("Wrong block size returned from getBlockSize() for " + name, 16 == blockSize);

        KeyParameter key = new KeyParameter(Hex.decode(tv[1]));
        byte[] plaintext = Hex.decode(tv[2]);
        byte[] ciphertext = Hex.decode(tv[3]);

        isTrue("Unexpected plaintext length for " + name, blockSize == plaintext.length);
        isTrue("Unexpected ciphertext length for " + name, blockSize == ciphertext.length);

        c.init(true, key);

        byte[] actual = new byte[blockSize];
        int num = c.processBlock(plaintext, 0, actual, 0);

        isTrue("Wrong length returned from processBlock() (encryption) for " + name, blockSize == num);
        isTrue("Incorrect ciphertext computed for " + name, Arrays.areEqual(ciphertext, actual));

        c.init(false, key);
        num = c.processBlock(ciphertext, 0, actual, 0);

        isTrue("Wrong length returned from processBlock() (decryption) for " + name, blockSize == num);
        isTrue("Incorrect plaintext computed for " + name, Arrays.areEqual(plaintext, actual));
    }

    private void checkTestVectors_RFC5794()
    {
        for (int i = 0; i < TEST_VECTORS_RFC5794.length; ++i)
        {
            checkTestVector_RFC5794(TEST_VECTORS_RFC5794[i]);
        }
    }

    public static void main(String[] args)
    {
        runTest(new ARIATest());
    }

    private class MyARIAEngine extends ARIAEngine
    {
        public void checkImplementation()
        {
            checkInvolution();
            checkSBoxes();
        }

        private void checkInvolution()
        {
            byte[] x = new byte[16], y = new byte[16];

            for (int i = 0; i < 100; ++i)
            {
                R.nextBytes(x);
                System.arraycopy(x, 0, y, 0, 16);
                A(y);
                A(y);
                ARIATest.this.isTrue(Arrays.areEqual(x, y));
            }
        }

        private void checkSBoxes()
        {
            for (int i = 0; i < 256; ++i)
            {
                byte x = (byte)i;

                ARIATest.this.isTrue(x == SB1(SB3(x)));
                ARIATest.this.isTrue(x == SB3(SB1(x)));

                ARIATest.this.isTrue(x == SB2(SB4(x)));
                ARIATest.this.isTrue(x == SB4(SB2(x)));
            }
        }
    }
}

@@ -1293,57 +1293,8 @@
 ();%0A
-        long before = System.currentTimeMillis();
 %0A   
@@ -1321,18 +1321,16 @@
  i %3C 100
-00
 ; ++i)%0A 
@@ -1342,24 +1342,28 @@
   %7B%0A        
+    
 checkRandomR
@@ -1388,155 +1388,8 @@
    %7D
-%0A        long after = System.currentTimeMillis();%0A        long elapsed = after - before;%0A        System.out.println(%22Elapsed: %22 + elapsed + %22ms.%22);
 %0A%0A  

Remove debugging code from ARIATest