package v2transport

import (
	"bytes"
	"encoding/hex"
	"strings"
	"testing"

	"github.com/btcsuite/btcd/btcec/v2"
	"github.com/btcsuite/btcd/btcec/v2/ellswift"
)

func setHex(hexString string) *btcec.FieldVal {
	if len(hexString)%2 != 0 {
		hexString = "0" + hexString
	}
	bytes, _ := hex.DecodeString(hexString)

	var f btcec.FieldVal
	f.SetByteSlice(bytes)

	return &f
}

const (
	mainNet = 0xd9b4bef9
)

func TestPacketEncodingVectors(t *testing.T) {
	tests := []struct {
		inIdx                 int
		inPrivOurs            string
		inEllswiftOurs        string
		inEllswiftTheirs      string
		inInitiating          bool
		inContents            string
		inMultiply            int
		inAad                 string
		inIgnore              bool
		midXOurs              string
		midXTheirs            string
		midXShared            string
		midSharedSecret       string
		midInitiatorL         string
		midInitiatorP         string
		midResponderL         string
		midResponderP         string
		midSendGarbageTerm    string
		midRecvGarbageTerm    string
		outSessionID          string
		outCiphertext         string
		outCiphertextEndsWith string
	}{
		{
			inIdx:                 1,
			inPrivOurs:            "61062ea5071d800bbfd59e2e8b53d47d194b095ae5a4df04936b49772ef0d4d7",
			inEllswiftOurs:        "ec0adff257bbfe500c188c80b4fdd640f6b45a482bbc15fc7cef5931deff0aa186f6eb9bba7b85dc4dcc28b28722de1e3d9108b985e2967045668f66098e475b",
			inEllswiftTheirs:      "a4a94dfce69b4a2a0a099313d10f9f7e7d649d60501c9e1d274c300e0d89aafaffffffffffffffffffffffffffffffffffffffffffffffffffffffff8faf88d5",
			inInitiating:          true,
			inContents:            "8e",
			inMultiply:            1,
			inAad:                 "",
			inIgnore:              false,
			midXOurs:              "19e965bc20fc40614e33f2f82d4eeff81b5e7516b12a5c6c0d6053527eba0923",
			midXTheirs:            "0c71defa3fafd74cb835102acd81490963f6b72d889495e06561375bd65f6ffc",
			midXShared:            "4eb2bf85bd00939468ea2abb25b63bc642e3d1eb8b967fb90caa2d89e716050e",
			midSharedSecret:       "c6992a117f5edbea70c3f511d32d26b9798be4b81a62eaee1a5acaa8459a3592",
			midInitiatorL:         "9a6478b5fbab1f4dd2f78994b774c03211c78312786e602da75a0d1767fb55cf",
			midInitiatorP:         "7d0c7820ba6a4d29ce40baf2caa6035e04f1e1cefd59f3e7e59e9e5af84f1f51",
			midResponderL:         "17bc726421e4054ac6a1d54915085aaa766f4d3cf67bbd168e6080eac289d15e",
			midResponderP:         "9f0fc1c0e85fd9a8eee07e6fc41dba2ff54c7729068a239ac97c37c524cca1c0",
			midSendGarbageTerm:    "faef555dfcdb936425d84aba524758f3",
			midRecvGarbageTerm:    "02cb8ff24307a6e27de3b4e7ea3fa65b",
			outSessionID:          "ce72dffb015da62b0d0f5474cab8bc72605225b0cee3f62312ec680ec5f41ba5",
			outCiphertext:         "7530d2a18720162ac09c25329a60d75adf36eda3c3",
			outCiphertextEndsWith: "",
		},
		{
			inIdx:                 999,
			inPrivOurs:            "1f9c581b35231838f0f17cf0c979835baccb7f3abbbb96ffcc318ab71e6e126f",
			inEllswiftOurs:        "a1855e10e94e00baa23041d916e259f7044e491da6171269694763f018c7e63693d29575dcb464ac816baa1be353ba12e3876cba7628bd0bd8e755e721eb0140",
			inEllswiftTheirs:      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000000000000000000000000000000000000000000000000000000000000000",
			inInitiating:          false,
			inContents:            "3eb1d4e98035cfd8eeb29bac969ed3824a",
			inMultiply:            1,
			inAad:                 "",
			inIgnore:              false,
			midXOurs:              "45b6f1f684fd9f2b16e2651ddc47156c0695c8c5cd2c0c9df6d79a1056c61120",
			midXTheirs:            "edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c",
			midXShared:            "c40eb6190caf399c9007254ad5e5fa20d64af2b41696599c59b2191d16992955",
			midSharedSecret:       "a0138f564f74d0ad70bc337dacc9d0bf1d2349364caf1188a1e6e8ddb3b7b184",
			midInitiatorL:         "b82a0a7ce7219777f914d2ab873c5c487c56bd7b68622594d67fe029a8fa7def",
			midInitiatorP:         "d760ba8f62dd3d29d7d5584e310caf2540285edc6b51c640f9497e99c3536fd2",
			midResponderL:         "9db0c6f9a903cbab5d7b3c58273a3421eec0001814ec53236bd405131a0d8e90",
			midResponderP:         "23d2b5e653e6a3a8db160a2ca03d11cb5a79983babba861fcb57c38413323c0c",
			midSendGarbageTerm:    "efb64fd80acd3825ac9bc2a67216535a",
			midRecvGarbageTerm:    "b3cb553453bceb002897e751ff7588bf",
			outSessionID:          "9267c54560607de73f18c563b76a2442718879c52dd39852885d4a3c9912c9ea",
			outCiphertext:         "1da1bcf589f9b61872f45b7fa5371dd3f8bdf5d515b0c5f9fe9f0044afb8dc0aa1cd39a8c4",
			outCiphertextEndsWith: "",
		},
		{
			inIdx:                 0,
			inPrivOurs:            "0286c41cd30913db0fdff7a64ebda5c8e3e7cef10f2aebc00a7650443cf4c60d",
			inEllswiftOurs:        "d1ee8a93a01130cbf299249a258f94feb5f469e7d0f2f28f69ee5e9aa8f9b54a60f2c3ff2d023634ec7f4127a96cc11662e402894cf1f694fb9a7eaa5f1d9244",
			inEllswiftTheirs:      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff22d5e441524d571a52b3def126189d3f416890a99d4da6ede2b0cde1760ce2c3f98457ae",
			inInitiating:          true,
			inContents:            "054290a6c6ba8d80478172e89d32bf690913ae9835de6dcf206ff1f4d652286fe0ddf74deba41d55de3edc77c42a32af79bbea2c00bae7492264c60866ae5a",
			inMultiply:            1,
			inAad:                 "[encoded data, 8190 characters]",
			inIgnore:              false,
			midXOurs:              "33a32d10066fa3963a9518a14d1bd1cb5ccaceaeaaeddb4d7aead90c08395bfd",
			midXTheirs:            "568146140669e69646a6ffeb3793e8010e2732209b4c34ec13e209a070109183",
			midXShared:            "a1017beaa8784f283dee185cd847ae3a327a981e62ae21e8c5face175fc97e9b",
			midSharedSecret:       "250b93570d411149105ab8cb0bc5079914906306368c23e9d77c2a33265b994c",
			midInitiatorL:         "4ec7daf7294a4a2c717442dd21cf2f052a3bfe9d535b55da0f66fecf87a27534",
			midInitiatorP:         "52ab4db9c4b06621f8ded3405691eb32465b1360d15a6b127ded4d15f9cde466",
			midResponderL:         "ba9906da802407ddedf6733e29f3996c62425e79d3cbfeebbd6ec4cdc7c976a8",
			midResponderP:         "ee661e18c97319ad071106bf35fe1085034832f70718d92f887932128b6100c7",
			midSendGarbageTerm:    "d4e3f18ac2e2095edb5c3b94236118ad",
			midRecvGarbageTerm:    "4faa6c4233d9fd53d170ede4172142a8",
			outSessionID:          "23f154ac43cfc59c4243e9fc68aeec8f19ad3942d74108e833b36f0dd3dcd357",
			outCiphertext:         "8da7de6ea7bf2a81a396a42880ba1f5756734c4821309ac9aeffa2a26ce86873b9dc4935a772de6ec5162c6d075b14536800fb174841153511bfb597e992e2fe8a450c4bce102cc550bb37fd564c4d60bf884e",
			outCiphertextEndsWith: "",
		},
		{
			inIdx:                 223,
			inPrivOurs:            "6c77432d1fda31e9f942f8af44607e10f3ad38a65f8a4bddae823e5eff90dc38",
			inEllswiftOurs:        "d2685070c1e6376e633e825296634fd461fa9e5bdf2109bcebd735e5a91f3e587c5cb782abb797fbf6bb5074fd1542a474f2a45b673763ec2db7fb99b737bbb9",
			inEllswiftTheirs:      "56bd0c06f10352c3a1a9f4b4c92f6fa2b26df124b57878353c1fc691c51abea77c8817daeeb9fa546b77c8daf79d89b22b0e1b87574ece42371f00237aa9d83a",
			inInitiating:          false,
			inContents:            "7e0e78eb6990b059e6cf0ded66ea93ef82e72aa2f18ac24f2fc6ebab561ae557420729da103f64cecfa20527e15f9fb669a49bbbf274ef0389b3e43c8c44e5f60bf2ac38e2b55e7ec4273dba15ba41d21f8f5b3ee1688b3c29951218caf847a97fb50d75a86515d445699497d968164bf740012679b8962de573be941c62b7ef",
			inMultiply:            1,
			inAad:                 "",
			inIgnore:              true,
			midXOurs:              "193d019db571162e52567e0cfdf9dd6964394f32769ae2edc4933b03b502d771",
			midXTheirs:            "2dd7b9cc85524f8670f695c3143ac26b45cebcabb2782a85e0fe15aee3956535",
			midXShared:            "5e35f94adfd57976833bffec48ef6dde983d18a55501154191ea352ef06732ee",
			midSharedSecret:       "1918b741ef5f9d1d7670b050c152b4a4ead2c31be9aecb0681c0cd4324150853",
			midInitiatorL:         "97124c56236425d792b1ec85e34b846e8d88c9b9f1d4f23ac6cdcc4c177055a0",
			midInitiatorP:         "8c71b468c61119415e3c1dfdd184134211951e2f623199629a46bff9673611f2",
			midResponderL:         "b43b8791b51ed682f56d64351601be28e478264411dcf963b14ee60b9ae427fa",
			midResponderP:         "794dde4b38ef04250c534a7fa638f2e8cc8b6d2c6110ec290ab0171fdf277d51",
			midSendGarbageTerm:    "cf2e25f23501399f30738d7eee652b90",
			midRecvGarbageTerm:    "225a477a28a54ea7671d2b217a9c29db",
			outSessionID:          "7ec02fea8c1484e3d0875f978c5f36d63545e2e4acf56311394422f4b66af612",
			outCiphertext:         "",
			outCiphertextEndsWith: "729847a3e9eba7a5bff454b5de3b393431ee360736b6c030d7a5bd01d1203d2e98f528543fd2bf886ccaa1ada5e215a730a36b3f4abfc4e252c89eb01d9512f94916dae8a76bf16e4da28986ffe159090fe5267ee3394300b7ccf4dfad389a26321b3a3423e4594a82ccfbad16d6561ecb8772b0cb040280ff999a29e3d9d4fd",
		},
		{
			inIdx:                 448,
			inPrivOurs:            "a6ec25127ca1aa4cf16b20084ba1e6516baae4d32422288e9b36d8bddd2de35a",
			inEllswiftOurs:        "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff053d7ecca53e33e185a8b9be4e7699a97c6ff4c795522e5918ab7cd6b6884f67e683f3dc",
			inEllswiftTheirs:      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa7730be30000000000000000000000000000000000000000000000000000000000000000",
			inInitiating:          true,
			inContents:            "00cf68f8f7ac49ffaa02c4864fdf6dfe7bbf2c740b88d98c50ebafe32c92f3427f57601ffcb21a3435979287db8fee6c302926741f9d5e464c647eeb9b7acaeda46e00abd7506fc9a719847e9a7328215801e96198dac141a15c7c2f68e0690dd1176292a0dded04d1f548aad88f1aebdc0a8f87da4bb22df32dd7c160c225b843e83f6525d6d484f502f16d923124fc538794e21da2eb689d18d87406ecced5b9f92137239ed1d37bcfa7836641a83cf5e0a1cf63f51b06f158e499a459ede41c",
			inMultiply:            1,
			inAad:                 "",
			inIgnore:              false,
			midXOurs:              "02b225089255f7b02b20276cfe9779144df8fb1957b477bff3239d802d1256e9",
			midXTheirs:            "5232c4b6bde9d3d45d7b763ebd7495399bb825cc21de51011761cd81a51bdc84",
			midXShared:            "379223d2f1ea7f8a22043c4ce4122623098309e15b1ce58286ebe3d3bf40f4e1",
			midSharedSecret:       "dd210aa6629f20bb328e5d89daa6eb2ac3d1c658a725536ff154f31b536c23b2",
			midInitiatorL:         "393472f85a5cc6b0f02c4bd466db7a2dc5b91fc9dcb15c0dd6dc21116ece8bca",
			midInitiatorP:         "c80b87b793db47320b2795db66d331bd3021cc24e360d59d0fa8974f54687e0c",
			midResponderL:         "ef16a43d77e2b270b0a145ee1618d35f3c943cc7877d6cfcff2287d41692be39",
			midResponderP:         "20d4b62e2d982c61bb0cc39a93283d98af36530ef12331d44b2477b0e521b490",
			midSendGarbageTerm:    "fead69be77825a23daec377c362aa560",
			midRecvGarbageTerm:    "511d4980526c5e64aa7187462faeafdd",
			outSessionID:          "acb8f084ea763ddd1b92ac4ed23bf44de20b84ab677d4e4e6666a6090d40353d",
			outCiphertext:         "",
			outCiphertextEndsWith: "77b4656934a82de1a593d8481f020194ddafd8cac441f9d72aeb8721e6a14f49698ca6d9b2b6d59d07a01aa552fd4d5b68d0d1617574c77dea10bfadbaa31b83885b7ceac2fd45e3e4a331c51a74e7b1698d81b64c87c73c5b9258b4d83297f9debc2e9aa07f8572ff434dc792b83ecf07b3197de8dc9cf7be56acb59c66cff5",
		},
		{
			inIdx:                 673,
			inPrivOurs:            "0af952659ed76f80f585966b95ab6e6fd68654672827878684c8b547b1b94f5a",
			inEllswiftOurs:        "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc81017fd92fd31637c26c906b42092e11cc0d3afae8d9019d2578af22735ce7bc469c72d",
			inEllswiftTheirs:      "9652d78baefc028cd37a6a92625b8b8f85fde1e4c944ad3f20e198bef8c02f19fffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e91870",
			inInitiating:          false,
			inContents:            "5c6272ee55da855bbbf7b1246d9885aa7aa601a715ab86fa46c50da533badf82b97597c968293ae04e",
			inMultiply:            97561,
			inAad:                 "",
			inIgnore:              false,
			midXOurs:              "4b1767466fe2fb8deddf2dc52cc19c7e2032007e19bfb420b30a80152d0f22d6",
			midXTheirs:            "64c383e0e78ac99476ddff2061683eeefa505e3666673a1371342c3e6c26981d",
			midXShared:            "5bcfeac98d87e87e158bf839f1269705429f7af2a25b566a25811b5f9aef9560",
			midSharedSecret:       "3568f2aea2e14ef4ee4a3c2a8b8d31bc5e3187ba86db10739b4ff8ec92ff6655",
			midInitiatorL:         "c7df866a62b7d404eb530b2be245a7aece0fb4791402a1de8f33530cbf777cc1",
			midInitiatorP:         "8f732e4aae2ba9314e0982492fa47954de9c189d92fbc549763b27b1b47642ce",
			midResponderL:         "992085edfecb92c62a3a7f96ea416f853f34d0dfe065b966b6968b8b87a83081",
			midResponderP:         "c5ba5eaf9e1c807154ebab3ea472499e815a7be56dfaf0c201cf6e91ffeca8e6",
			midSendGarbageTerm:    "5e2375ac629b8df1e4ff3617c6255a70",
			midRecvGarbageTerm:    "70bcbffcb62e4d29d2605d30bceef137",
			outSessionID:          "7332e92a3f9d2792c4d444fac5ed888c39a073043a65eefb626318fd649328f8",
			outCiphertext:         "",
			outCiphertextEndsWith: "657a4a19711ce593c3844cb391b224f60124aba7e04266233bc50cafb971e26c7716b76e98376448f7d214dd11e629ef9a974d60e3770a695810a61c4ba66d78b936ee7892b98f0b48ddae9fcd8b599dca1c9b43e9b95e0226cf8d4459b8a7c2c4e6db80f1d58c7b20dd7208fa5c1057fb78734223ee801dbd851db601fee61e",
		},
		{
			inIdx:                 1024,
			inPrivOurs:            "f90e080c64b05824c5a24b2501d5aeaf08af3872ee860aa80bdcd430f7b63494",
			inEllswiftOurs:        "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff115173765dc202cf029ad3f15479735d57697af12b0131dd21430d5772e4ef11474d58b9",
			inEllswiftTheirs:      "12a50f3fafea7c1eeada4cf8d33777704b77361453afc83bda91eef349ae044d20126c6200547ea5a6911776c05dee2a7f1a9ba7dfbabbbd273c3ef29ef46e46",
			inInitiating:          true,
			inContents:            "5f67d15d22ca9b2804eeab0a66f7f8e3a10fa5de5809a046084348cbc5304e843ef96f59a59c7d7fdfe5946489f3ea297d941bac326225df316a25fc90f0e65b0d31a9c497e960fdbf8c482516bc8a9c1c77b7f6d0e1143810c737f76f9224e6f2c9af5186b4f7259c7e8d165b6e4fe3d38a60bdbdd4d06ecdcaaf62086070dbb68686b802d53dfd7db14b18743832605f5461ad81e2af4b7e8ff0eff0867a25b93cec7becf15c43131895fed09a83bf1ee4a87d44dd0f02a837bf5a1232e201cb882734eb9643dc2dc4d4e8b5690840766212c7ac8f38ad8a9ec47c7a9b3e022ae3eb6a32522128b518bd0d0085dd81c5",
			inMultiply:            69615,
			inAad:                 "",
			inIgnore:              true,
			midXOurs:              "8b8de966150bf872b4b695c9983df519c909811954d5d76e99ed0d5f1860247b",
			midXTheirs:            "eef379db9bd4b1aa90fc347fad33f7d53083389e22e971036f59f4e29d325ac2",
			midXShared:            "0a402d812314646ccc2565c315d1429ec1ed130ff92ff3f48d948f29c3762cf1",
			midSharedSecret:       "e25461fb0e4c162e18123ecde88342d54d449631e9b75a266fd9260c2bb2f41d",
			midInitiatorL:         "97771ce2ce17a25c3d65bf9f8e4acb830dce8d41392be3e4b8ed902a3106681a",
			midInitiatorP:         "2e7022b4eae9152942f68160a93e25d3e197a557385594aa587cb5e431bb470d",
			midResponderL:         "613f85a82d783ce450cfd7e91a027fcc4ad5610872f83e4dbe9e2202184c6d6e",
			midResponderP:         "cb5de4ed1083222e381401cf88e3167796bc9ab5b8aa1f27b718f39d1e6c0e87",
			midSendGarbageTerm:    "b709dea25e0be287c50e3603482c2e98",
			midRecvGarbageTerm:    "1f677e9d7392ebe3633fd82c9efb0f16",
			outSessionID:          "889f339285564fd868401fac8380bb9887925122ec8f31c8ae51ce067def103b",
			outCiphertext:         "",
			outCiphertextEndsWith: "7c4b9e1e6c1ce69da7b01513cdc4588fd93b04dafefaf87f31561763d906c672bac3dfceb751ebd126728ac017d4d580e931b8e5c7d5dfe0123be4dc9b2d2238b655c8a7fadaf8082c31e310909b5b731efc12f0a56e849eae6bfeedcc86dd27ef9b91d159256aa8e8d2b71a311f73350863d70f18d0d7302cf551e4303c7733",
		},
	}

	for _, test := range tests {
		inInitiating := test.inInitiating

		// We need to convert the FieldVal into a ModNScalar so that we
		// can use the ScalarBaseMultNonConst.
		inPrivOurs := setHex(test.inPrivOurs)
		inPrivOursBytes := inPrivOurs.Bytes()

		var inPrivOursScalar btcec.ModNScalar
		overflow := inPrivOursScalar.SetBytes(inPrivOursBytes)
		if overflow == 1 {
			t.Fatalf("unexpected reduction")
		}

		var inPubOurs btcec.JacobianPoint
		btcec.ScalarBaseMultNonConst(&inPrivOursScalar, &inPubOurs)
		inPubOurs.ToAffine()

		midXOurs := setHex(test.midXOurs)
		if !midXOurs.Equals(&inPubOurs.X) {
			t.Fatalf("expected mid-state to match our public key")
		}

		// ellswift_decode takes in ellswift_bytes and returns a proper key.
		// 1. convert from hex to bytes
		bytesEllswiftOurs, err := hex.DecodeString(test.inEllswiftOurs)
		if err != nil {
			t.Fatalf("unexpected error decoding string")
		}

		uEllswiftOurs := bytesEllswiftOurs[:32]
		tEllswiftOurs := bytesEllswiftOurs[32:]

		var (
			uEllswiftOursFV btcec.FieldVal
			tEllswiftOursFV btcec.FieldVal
		)

		truncated := uEllswiftOursFV.SetByteSlice(uEllswiftOurs)
		if truncated {
			uEllswiftOursFV.Normalize()
		}

		truncated = tEllswiftOursFV.SetByteSlice(tEllswiftOurs)
		if truncated {
			tEllswiftOursFV.Normalize()
		}

		xEllswiftOurs, err := ellswift.XSwiftEC(
			&uEllswiftOursFV, &tEllswiftOursFV,
		)
		if err != nil {
			t.Fatalf("unexpected error during XSwiftEC")
		}

		if !midXOurs.Equals(xEllswiftOurs) {
			t.Fatalf("expected mid-state to match decoded " +
				"ellswift key")
		}

		bytesEllswiftTheirs, err := hex.DecodeString(
			test.inEllswiftTheirs,
		)
		if err != nil {
			t.Fatalf("unexpected error decoding string")
		}

		uEllswiftTheirs := bytesEllswiftTheirs[:32]
		tEllswiftTheirs := bytesEllswiftTheirs[32:]

		var (
			uEllswiftTheirsFV btcec.FieldVal
			tEllswiftTheirsFV btcec.FieldVal
		)

		truncated = uEllswiftTheirsFV.SetByteSlice(uEllswiftTheirs)
		if truncated {
			uEllswiftTheirsFV.Normalize()
		}

		truncated = tEllswiftTheirsFV.SetByteSlice(tEllswiftTheirs)
		if truncated {
			tEllswiftTheirsFV.Normalize()
		}

		xEllswiftTheirs, err := ellswift.XSwiftEC(
			&uEllswiftTheirsFV, &tEllswiftTheirsFV,
		)
		if err != nil {
			t.Fatalf("unexpected error during XSwiftEC")
		}

		midXTheirs := setHex(test.midXTheirs)
		if !midXTheirs.Equals(xEllswiftTheirs) {
			t.Fatalf("expected mid-state to match decoded " +
				"ellswift key")
		}

		privKeyOurs, _ := btcec.PrivKeyFromBytes((*inPrivOursBytes)[:])

		var bytesEllswiftTheirs64 [64]byte
		copy(bytesEllswiftTheirs64[:], bytesEllswiftTheirs)

		xShared, err := ellswift.EllswiftECDHXOnly(
			bytesEllswiftTheirs64, privKeyOurs,
		)
		if err != nil {
			t.Fatalf("unexpected error when computing shared x")
		}

		var xSharedFV btcec.FieldVal
		overflow = xSharedFV.SetBytes(&xShared)
		if overflow == 1 {
			t.Fatalf("unexpected truncation")
		}

		midXShared := setHex(test.midXShared)

		if !midXShared.Equals(&xSharedFV) {
			t.Fatalf("expected mid-state x shared")
		}

		var bytesEllswiftOurs64 [64]byte
		copy(bytesEllswiftOurs64[:], bytesEllswiftOurs)

		sharedSecret, err := ellswift.V2Ecdh(
			privKeyOurs, bytesEllswiftTheirs64,
			bytesEllswiftOurs64, inInitiating,
		)
		if err != nil {
			t.Fatalf("unexpected error when calculating " +
				"shared secret")
		}

		midShared, err := hex.DecodeString(test.midSharedSecret)
		if err != nil {
			t.Fatalf("unexpected hex decode failure")
		}

		if !bytes.Equal(midShared, sharedSecret[:]) {
			t.Fatalf("expected mid shared secret")
		}

		p := NewPeer()

		buf := bytes.NewBuffer(nil)
		p.UseReadWriter(buf)

		err = p.createV2Ciphers(midShared, inInitiating, mainNet)
		if err != nil {
			t.Fatalf("error initiating v2 transport")
		}

		midInitiatorL, err := hex.DecodeString(test.midInitiatorL)
		if err != nil {
			t.Fatalf("unexpected error decoding midInitiatorL")
		}

		if !bytes.Equal(midInitiatorL, p.initiatorL) {
			t.Fatalf("expected mid-state initiatorL to " +
				"match computed value")
		}

		midInitiatorP, err := hex.DecodeString(test.midInitiatorP)
		if err != nil {
			t.Fatalf("unexpected error decoding midInitiatorP")
		}

		if !bytes.Equal(midInitiatorP, p.initiatorP) {
			t.Fatalf("expected mid-state initiatorP to " +
				"match computed value")
		}

		midResponderL, err := hex.DecodeString(test.midResponderL)
		if err != nil {
			t.Fatalf("unexpected error decoding midResponderL")
		}

		if !bytes.Equal(midResponderL, p.responderL) {
			t.Fatalf("expected mid-state responderL to " +
				"match computed value")
		}

		midResponderP, err := hex.DecodeString(test.midResponderP)
		if err != nil {
			t.Fatalf("unexpected error decoding midResponderP")
		}

		if !bytes.Equal(midResponderP, p.responderP) {
			t.Fatalf("expected mid-state responderP to " +
				"match computed value")
		}

		midSendGarbageTerm, err := hex.DecodeString(
			test.midSendGarbageTerm,
		)
		if err != nil {
			t.Fatalf("unexpected error decoding midSendGarbageTerm")
		}

		if !bytes.Equal(midSendGarbageTerm, p.sendGarbageTerm[:]) {
			t.Fatalf("expected mid-state sendGarbageTerm " +
				"to match computed value")
		}

		midRecvGarbageTerm, err := hex.DecodeString(
			test.midRecvGarbageTerm,
		)
		if err != nil {
			t.Fatalf("unexpected error decoding midRecvGarbageTerm")
		}

		if !bytes.Equal(midRecvGarbageTerm, p.recvGarbageTerm) {
			t.Fatalf("expected mid-state recvGarbageTerm to " +
				"match computed value")
		}

		outSessionID, err := hex.DecodeString(test.outSessionID)
		if err != nil {
			t.Fatalf("unexpected error decoding outSessionID")
		}

		if !bytes.Equal(outSessionID, p.sessionID) {
			t.Fatalf("expected sessionID to match computed value")
		}

		for i := 0; i < test.inIdx; i++ {
			_, _, err = p.V2EncPacket([]byte{}, []byte{}, false)
			if err != nil {
				t.Fatalf("unexpected error while encrypting packet")
			}
		}

		initialContents, err := hex.DecodeString(test.inContents)
		if err != nil {
			t.Fatalf("unexpected error decoding contents")
		}

		aad, err := hex.DecodeString(test.inAad)
		if err != nil {
			t.Fatalf("unexpected error decoding aad")
		}

		var contents []byte

		copy(contents, initialContents)

		for i := 0; i < test.inMultiply; i++ {
			contents = append(contents, initialContents...)
		}

		ciphertext, _, err := p.V2EncPacket(contents, aad, test.inIgnore)
		if err != nil {
			t.Fatalf("unexpected error when encrypting packet: %v", err)
		}

		if len(test.outCiphertext) != 0 {
			outCiphertextBytes, err := hex.DecodeString(test.outCiphertext)
			if err != nil {
				t.Fatalf("unexpected error decoding outCiphertext: %v", err)
			}

			if !bytes.Equal(outCiphertextBytes, ciphertext) {
				t.Fatalf("ciphertext mismatch")
			}
		}

		if len(test.outCiphertextEndsWith) != 0 {
			ciphertextHex := hex.EncodeToString(ciphertext)
			if !strings.HasSuffix(ciphertextHex, test.outCiphertextEndsWith) {
				t.Fatalf("suffix mismatch")
			}
		}
	}
}
