package gcm

import (
	"bytes"
	"crypto/cipher"
	"encoding/hex"
	"fmt"
	"testing"

	"xdx.jelly/xgcl/sm/sm4"
)

func TestGCM(t *testing.T) {
	key, _ := hex.DecodeString("11754cd72aec309bf52f7687212e8957")
	block, _ := sm4.NewCipher(key)
	aead, _ := NewGCM(block)
	gcm := aead.(*gcm)

	f1 := &gcmFieldElement{
		low:  0,
		high: 1,
	}
	// f2 := &gcmFieldElement{
	// 	low:  0,
	// 	high: 0x8000000000000000,
	// }

	gcm.mul(f1)
	fmt.Printf("%016x %016x\n", f1.high, f1.low)

}

// sm4_GCM模式
var sm4GCMTests = []struct {
	key, nonce, plaintext, ad, result string
}{
	{
		"11754cd72aec309bf52f7687212e8957",
		"3c819d9a9bed087615030b65", // nonce should be 12 bytes.
		"plaintext",
		"additional message not need encrypt, empty is ok",
		"6111f78f2f82b913c20e333160bfec034c3720ac133a6203b1",
	},
}

func TestSM4GCM(t *testing.T) {

	for i, test := range sm4GCMTests {
		key, _ := hex.DecodeString(test.key)
		var sm4gcm cipher.AEAD
		var err error
		// user cipher.NewGCM
		block, err := sm4.NewCipher(key)
		if err != nil {
			t.Fatal(err)
		}
		sm4gcm, err = NewGCM(block)

		if err != nil {
			t.Fatal(err)
		}

		nonce, _ := hex.DecodeString(test.nonce)
		plaintext := []byte(test.plaintext)

		ad := []byte(test.ad)
		fmt.Printf("plaintext:%x\n", plaintext)
		ct := sm4gcm.Seal(plaintext[:0], nonce, plaintext, ad)

		fmt.Printf("plaintext: %x\n", plaintext)
		fmt.Printf("cipherText: %x\n", ct)

		if ctHex := hex.EncodeToString(ct); ctHex != test.result {
			t.Errorf("#%d: got %s, want %s", i, ctHex, test.result)
			continue
		}

		plaintext2, err := sm4gcm.Open(ct[:0], nonce, ct, ad)
		if err != nil {
			t.Errorf("#%d: Open failed", i)
			continue
		}

		if !bytes.Equal(plaintext, plaintext2) {
			t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
			continue
		}

		// if ad, nonce, ct was changed, return err
		if len(ad) > 0 {
			ad[0] ^= 0x80
			if _, err := sm4gcm.Open(nil, nonce, ct, ad); err == nil {
				t.Errorf("#%d: Open was successful after altering additional data", i)
			}
			ad[0] ^= 0x80
		}

		nonce[0] ^= 0x80
		if _, err := sm4gcm.Open(nil, nonce, ct, ad); err == nil {
			t.Errorf("#%d: Open was successful after altering nonce", i)
		}
		nonce[0] ^= 0x80

		ct[0] ^= 0x80
		if _, err := sm4gcm.Open(nil, nonce, ct, ad); err == nil {
			t.Errorf("#%d: Open was successful after altering ciphertext", i)
		}
		ct[0] ^= 0x80
	}
}
