package blockmode_test

import (
	"bytes"
	"crypto/aes"
	"encoding/hex"
	"testing"

	"xdx.jelly/xgcl/utils/blockmode"
)

// Test vectors in sp800-38c
var aesCcmTests = []struct {
	key, nonce, plaintext, ad, result string
	tagSize                           int
	adRepeats                         int // repeat additional data adRepeats times
}{
	{
		"404142434445464748494a4b4c4d4e4f",
		"10111213141516",
		"20212223",
		"0001020304050607",
		"7162015b4dac255d",
		4, 1,
	},

	{
		"404142434445464748494a4b4c4d4e4f",
		"1011121314151617",
		"202122232425262728292a2b2c2d2e2f",
		"000102030405060708090a0b0c0d0e0f",
		"d2a1f0e051ea5f62081a7792073d593d1fc64fbfaccd",
		6, 1,
	},
	{
		"404142434445464748494a4b4c4d4e4f",
		"101112131415161718191a1b",
		"202122232425262728292a2b2c2d2e2f3031323334353637",
		"000102030405060708090a0b0c0d0e0f10111213",
		"e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5484392fbc1b09951",
		8, 1,
	},
	{
		"404142434445464748494a4b4c4d4e4f",
		"101112131415161718191a1b1c",
		"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
		"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
		"69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72b4ac6bec93e8598e7f0dadbcea5b",
		14, 256,
	},
}

func TestAesCCM(t *testing.T) {
	for _, test := range aesCcmTests {
		key, _ := hex.DecodeString(test.key)
		nonce, _ := hex.DecodeString(test.nonce)
		plaintext, _ := hex.DecodeString(test.plaintext)
		ad1, _ := hex.DecodeString(test.ad)
		ad := make([]byte, 0, len(ad1)*test.adRepeats)
		for i := 0; i < test.adRepeats; i++ {
			ad = append(ad, ad1...)
		}
		result, _ := hex.DecodeString(test.result)
		tagSize := test.tagSize

		b, err := aes.NewCipher(key)
		if err != nil {
			t.Fatal(err)
		}
		aesBlockMode := blockmode.Wrap(b)
		ccm, err := blockmode.NewCCMWithNonceAndTagSize(aesBlockMode, len(nonce), tagSize)
		if err != nil {
			t.Fatal(err)
		}
		ciphertext := ccm.Seal(nil, nonce, plaintext, ad)

		if bytes.Compare(ciphertext, result) != 0 {
			t.Fatal("result unequal expected")
		}

		plaintext2, err := ccm.Open(nil, nonce, ciphertext, ad)
		if err != nil {
			t.Fatal(err)
		}
		if bytes.Compare(plaintext2, plaintext) != 0 {
			t.Fatal("decrypted plaintext not equal expected")
		}
	}

}
