package experiment

import (
	"crypto/rand"
	"fmt"
	"testing"

	"xdx.jelly/xgcl/grand"
)

func TestAes(t *testing.T) {

	// Output the aes sbox
	for i := 0; i < 16; i++ {
		for j := 0; j < 16; j++ {
			in := byte(i<<4 + j)
			fmt.Printf("0x%02x, ", aesSBox(in))
		}
		fmt.Println("")
	}
}

func TestAesni(t *testing.T) {
	// fmt.Printf("%x\n", rsh(0x89ABCDEF, 16))
	// Original data: 0x8899aabbccddeeff0123456789abcdef
	// Encoded data: 0x4b04f98cf4c860f8b6dd7df25d7ab320
	a := []uint32{0x89ABCDEF, 0x01234567, 0xCCDDEEFF, 0x8899AABB}
	key := []uint32{0x99BBDDFF, 0x11335577, 0x88AACCEE, 0x00224466}

	res := aesni(a, key)
	fmt.Printf("%x\n", res)
}
func TestSm4(t *testing.T) {
	for i := 0; i < 16; i++ {
		for j := 0; j < 16; j++ {
			in := byte(i<<4 + j)
			fmt.Printf("0x%02x ", sm4SBox(in))
		}
		fmt.Println("")
	}
}

func TestMul(t *testing.T) {
	// v1 := []int{0, 0, 0, 0, 0, 0, 0, 0, 1} // x^8
	// v2 := []int{1, 1}                      // 1 + x^2
	// fmt.Println(add(v1, v2))
	fmt.Println(aesField.Mul(NewFFE(0x11), NewFFE(0x11)))
	fmt.Println(aesField.Add(NewFFE(0x11), NewFFE(0x11)))

	// fmt.Println(invert(v2))
}

func TestXor(t *testing.T) {
	for {
		key := make([]byte, 16)
		rand.Read(key)
		p1 := make([]byte, 16)
		AesRound(p1, key)

		p2 := make([]byte, 16)
		p2[0] = 1
		AesRound(p2, key)

		fmt.Printf("%02X\n", p1)
		fmt.Printf("%02X\n", p2)
		fmt.Printf("s4+s'4 = %02X\n", p1[4]^p2[4])
		for i := 0; i < 16; i++ {
			if p1[i] != p2[i] {
				fmt.Printf("%d,", i)
			}
		}
		if p1[0]^p2[0] == 2 {
			fmt.Printf("key[0] = %02X\n", key[0])
		}
	}
}

func TestPossibleKey(t *testing.T) {
	for i := 0; i < 256; i++ {
		key := make([]byte, 16)
		key[0] = byte(i)
		p1 := make([]byte, 16)
		AesRound(p1, key)

		p2 := make([]byte, 16)
		p2[0] = 1
		AesRound(p2, key)
		fmt.Println(key[0], p2[0], p1[0], p2[0]+p1[0])
		if p1[0]+p2[0] == 2 {
			fmt.Printf("key[0] = %02X\n", key[0])
		}
	}
}

func TestCommutation(t *testing.T) {
	s := &ffe{}
	copy(s.v[:], grand.GetRandom(8))
	for i := 0; i < 8; i++ {
		s.v[i] = s.v[i] & 1
	}
	fmt.Println(s)
	r1 := mapToAesField(sm4Field.Invert(s))
	r2 := aesField.Invert(mapToAesField(s))

	fmt.Println(r1)
	fmt.Println(r2)
}

var C1 = &ffe{v: [8]byte{0, 1, 1, 1, 1, 1, 0, 0}} // 0x3e

var C2 = &ffe{v: [8]byte{0, 0, 1, 1, 0, 1, 1, 0}} // 0x6c

func TestComputeAffine(t *testing.T) {
	for i := 0; i < 255; i++ {
		s := NewFFE(byte(i))

		r1 := sm4SBox(s.Byte())

		r2 := Transform(M1, s)
		r2 = aesField.Add(r2, C1)
		r2 = NewFFE(aesSBox(r2.Byte()))
		r2 = Transform(M2, r2)
		r2 = aesField.Add(r2, C2)
		if r1 != r2.Byte() {
			t.Fatal("s=", s, "; r1=", r1, "; r2=", r2)
		}
	}
}
