package meerkat.mixer;

import org.spongycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import org.junit.Before;

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

/**
 * Created by Tzlil on 3/20/2016.
 */
public class SimpleRerandomizeTest {

    Random rand;
    ECGroup group;
    ECPoint g ;
    ECPoint h ;
    BigInteger sk;
    @Before
    public void setup() throws Exception {
        rand = new Random();
        group = new ECGroup("secp256k1");
        g = group.getGenerator();
        sk = random();
        h = g.multiply(sk);
    }

    public BigInteger random(){
        return new BigInteger(256,rand).mod(group.orderUpperBound());
    }

    public ECPoint randomMessage(){
        return group.sample(rand);
    }

    public Encryption encrypt(ECPoint message,BigInteger randomness){
        return new Encryption(g.multiply(randomness), message.add(h.multiply(randomness)));
    }

    public Encryption rerandomize(Encryption encryption,BigInteger randomness){
        return new Encryption(encryption.a.add(g.multiply(randomness)),encryption.b.add(h.multiply(randomness)));
    }

    public ECPoint decrypt(Encryption encryption){
        return encryption.a.multiply(sk).negate().add(encryption.b);
    }

    public class Encryption{
        ECPoint a,b;
        Encryption(ECPoint a, ECPoint b){
            this.a = a;
            this.b = b;
        }
    }

    public void oneRerandomizeTest(){
        ECPoint message = randomMessage();
        Encryption e = encrypt(message,random());
        BigInteger r = random();
        Encryption eNew = rerandomize(e,r);
        assert (decrypt(e).equals(message));
        assert (decrypt(eNew).equals(message));

        ECPoint expected1 = g.multiply(r);
        ECPoint result1 = group.add(eNew.a,e.a.negate());
        expected1.normalize();
        result1.normalize();
        assert (expected1.equals(result1));

        ECPoint expected2 = h.multiply(r);
        ECPoint result2 = group.add(eNew.b,e.b.negate());
        expected2.normalize();
        result2.normalize();
        assert (expected2.equals(result2));
    }


    @org.junit.Test
    public void rerandomizeTest(){

        int tests = 1000;

        for (int i = 0; i < tests; i ++){
            System.out.println("rerandomize test #" + i);
            oneRerandomizeTest();
        }
    }
}
