/*
 This file is part of GNUnet.
  (C) 2012, 2013 Christian Grothoff (and other contributing authors)

  GNUnet is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published
  by the Free Software Foundation; either version 3, or (at your
  option) any later version.

  GNUnet is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with GNUnet; see the file COPYING.  If not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.
 */

package org.gnunet.util;

import org.gnunet.util.crypto.Ed25519;
import org.junit.Assert;
import org.junit.Test;

import java.math.BigInteger;
import java.util.Random;

public class Ed25519Test {

    /**
     * Simple test for commutativity.
     */
    @Test
    public void test_commutative() {
        Ed25519 p1 = Ed25519.B.scalarmult(BigInteger.valueOf(42)).scalarmult(BigInteger.valueOf(100));
        Ed25519 p2 = Ed25519.B.scalarmult(BigInteger.valueOf(100)).scalarmult(BigInteger.valueOf(42));

        byte[] data1 = p1.encode();
        byte[] data2 = p2.encode();
        Assert.assertArrayEquals(data1, data2);
    }


    /**
     * Raw ECDH check.
     */
    @Test
    public void test_ecdh() {
        for (int i = 0; i < 5; ++i) {
            System.out.println("try " + i);
            byte[] d1 = new byte[32];
            byte[] d2 = new byte[32];
            Random r = new Random();
            r.nextBytes(d1);
            r.nextBytes(d2);
            d1[0] &= 248;
            d1[31] &= 127;
            d1[31] |= 64;
            d2[0] &= 248;
            d2[31] &= 127;
            d2[31] |= 64;


            Ed25519 pk1 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d1));
            Ed25519 pk2 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d2));
            byte[] pk1Data = pk1.encode();
            byte[] pk2Data = pk2.encode();

            Assert.assertEquals(pk1, Ed25519.decode(pk1Data));
            Assert.assertEquals(pk2, Ed25519.decode(pk2Data));



            byte[] data1 = Ed25519.decode(pk1Data).scalarmult(Ed25519.decodeScalar(d2)).encode();
            byte[] data2 = Ed25519.decode(pk2Data).scalarmult(Ed25519.decodeScalar(d1)).encode();



            /*
            Ed25519 p1 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d1)).scalarmult(Ed25519.decodeScalar(d2));
            Ed25519 p2 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d2)).scalarmult(Ed25519.decodeScalar(d1));
            byte[] data1 = p1.encode();
            byte[] data2 = p2.encode();
            */

            Assert.assertArrayEquals(data1, data2);
        }
    }

    /**
     * Test if decode is the inverse of encode.
     */
    @Test
    public void test_encode_inverse() {
        Random r = new Random();
        for (int i = 0; i < 5; i++) {
            byte[] d1 = new byte[32];
            r.nextBytes(d1);
            d1[31] &= 127;
            Ed25519 p1 = Ed25519.B.scalarmult(Ed25519.decodeScalar(d1));
            // encode and decode the same value!
            byte[] data1 = p1.encode();
            Ed25519 p2 = Ed25519.decode(data1);
            Assert.assertEquals(p1, p2);
            Assert.assertArrayEquals(p1.encode(), p2.encode());
        }
    }

    @Test
    public void test_encode_inverse_simple() {
        Ed25519 p1 = Ed25519.B;
        // encode and decode the same value!
        byte[] data1 = p1.encode();
        for (int i = 0; i < 32; i++) {
            System.out.print(data1[i] + " ");
        }
        System.out.println();
        Ed25519 p2 = Ed25519.decode(data1);
        Assert.assertArrayEquals(p1.encode(), p2.encode());
        Assert.assertEquals(p1, p2);
    }

    /**
     *
     */
    @Test
    public void test_encode_scalar() {
        Random r = new Random();
        for (int i = 0; i < 10; i++) {
            byte[] d1 = new byte[32];
            r.nextBytes(d1);
            d1[31] &= 127;
            BigInteger s1 = Ed25519.decodeScalar(d1);
            byte[] d2 = Ed25519.encodeScalar(s1);
            BigInteger s2 = Ed25519.decodeScalar(d2);
            Assert.assertEquals(s1, s2);
            Assert.assertArrayEquals(d1, d2);
        }
    }

    @Test
    public void test_order() {
        Ed25519 P = Ed25519.B.scalarmult(Ed25519.l);
        System.out.println("Point P: " + P);
        Assert.assertTrue(P.isIdentity());
    }
}
