// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mldsa_test

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

	"github.com/google/go-cmp/cmp"
	"github.com/tink-crypto/tink-go/v2/core/cryptofmt"
	"github.com/tink-crypto/tink-go/v2/insecuresecretdataaccess"
	"github.com/tink-crypto/tink-go/v2/internal/keygenregistry"
	"github.com/tink-crypto/tink-go/v2/key"
	"github.com/tink-crypto/tink-go/v2/secretdata"
	"github.com/tink-crypto/tink-go/v2/signature/mldsa"
)

func TestNewParameters(t *testing.T) {
	for _, tc := range []struct {
		name     string
		instance mldsa.Instance
		variant  mldsa.Variant
	}{
		{
			name:     "tink ML-DSA-65",
			instance: mldsa.MLDSA65,
			variant:  mldsa.VariantTink,
		},
		{
			name:     "tink ML-DSA-87",
			instance: mldsa.MLDSA87,
			variant:  mldsa.VariantTink,
		},
		{
			name:     "no prefix ML-DSA-65",
			instance: mldsa.MLDSA65,
			variant:  mldsa.VariantNoPrefix,
		},
		{
			name:     "no prefix ML-DSA-87",
			instance: mldsa.MLDSA87,
			variant:  mldsa.VariantNoPrefix,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, tc.variant)
			if err != nil {
				t.Errorf("mldsa.NewParameters(%v, %v) err = %v, want nil", tc.instance, tc.variant, err)
			}
			if got := params.Variant(); got != tc.variant {
				t.Errorf("params.Variant() = %v, want %v", got, tc.variant)
			}
		})
	}
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run("unknown", func(t *testing.T) {
			if _, err := mldsa.NewParameters(inst, mldsa.VariantUnknown); err == nil {
				t.Errorf("mldsa.NewParameters(%v, %v) err = nil, want error", inst, mldsa.VariantUnknown)
			}
		})
	}
}

func TestParametersHasIDRequirement(t *testing.T) {
	for _, tc := range []struct {
		name     string
		instance mldsa.Instance
		variant  mldsa.Variant
		want     bool
	}{
		{
			name:     "tink ML-DSA-65",
			instance: mldsa.MLDSA65,
			variant:  mldsa.VariantTink,
			want:     true,
		},
		{
			name:     "tink ML-DSA-87",
			instance: mldsa.MLDSA87,
			variant:  mldsa.VariantTink,
			want:     true,
		},
		{
			name:     "no prefix ML-DSA-65",
			instance: mldsa.MLDSA65,
			variant:  mldsa.VariantNoPrefix,
			want:     false,
		},
		{
			name:     "no prefix ML-DSA-87",
			instance: mldsa.MLDSA87,
			variant:  mldsa.VariantNoPrefix,
			want:     false,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, tc.variant)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v, %v) err = %v, want nil", tc.instance, tc.variant, err)
			}
			if got := params.HasIDRequirement(); got != tc.want {
				t.Errorf("params.HasIDRequirement() = %v, want %v", got, tc.want)
			}
		})
	}
}

func TestParametersEqual(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			tinkVariant, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			noPrefixVariant, err := mldsa.NewParameters(inst, mldsa.VariantNoPrefix)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want	 nil", mldsa.VariantNoPrefix, err)
			}

			if !tinkVariant.Equal(tinkVariant) {
				t.Errorf("tinkVariant.Equal(tinkVariant) = false, want true")
			}
			if !noPrefixVariant.Equal(noPrefixVariant) {
				t.Errorf("noPrefixVariant.Equal(noPrefixVariant) = false, want true")
			}
			if tinkVariant.Equal(noPrefixVariant) {
				t.Errorf("tinkVariant.Equal(noPrefixVariant) = true, want false")
			}
		})
	}
}

const (
	// Copied from Tink C++ ML-DSA signature verification test.
	privKey65Hex = "7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2D"
	pubKey65Hex  = "1483236FC9F943D98417809E95405384530ED83E151E8465D34E4638F1F8D7058D62E19A" +
		"B806490883A823176D4DC8A3C10C9960D0E948A9F7B62CA8E118DE5D7A05BB18E8018B6C" +
		"ACB4FE7885490599939D90D004BD480B116F5D6627B6C4C1B2A1496CC3525EF9F19953EC" +
		"63CDD6EBDB21D65B27C644194916AAD07CC559B08CFC1282D25D7276C9E5062E0B1C4CF1" +
		"11C0A9DCC49BF40F5ED3C27CB4E78E39C1F068736A788E2ED4A02E9EF23EACE802CD295B" +
		"6EB97D533091B3293D9BAD2938DFDECF2C4F9F6387B38A7FD22738A010B85949688650B6" +
		"F063B6BC6350A1E84C869FB3BBCDC4BF6C0D0674D7C07F7AE78E4BBB302B6DB8488B5F91" +
		"64E5E264682E45E71B58FC19ADF5EA892439EB352AFDDB63D22177AEF17261909E3F87BC" +
		"C7E1B1A58CD5DE8F8A886A12D7137CE5BFBD2C53ECEBFD1B9F2298583D767E0DB5178B95" +
		"2F4D069D66FDEDCA1FBDCF8720AAAA5313C0500ECF95B9B70E7E3D58DD2B57433D3A0637" +
		"DF36E964B21F44F791B3AF9074D6DBC9A2FC041D9E22D5E387C4081E6D4CCE6AB11FC8B4" +
		"F2C718EB2A19924E3F17EA1F44D0084B5D5296A97A3624E4E1F6CA05229F2888557AAB57" +
		"7FD72F8DC328F0E4F45DD13A191920F671ACE3BC29DC3195E951D0F5EEAA095A3D5F20E4" +
		"E4EA1AC157261C1C514AEB6940E63053AD68383F14E923602E6B241E9813246B47F009DB" +
		"446FBF61246BAD7ED386647D020A854CCA39ECAE5FA6D667CB6D433F02BC2FAB9F37096F" +
		"3C127741EC02A46C81022E070AE1DF54623DF44C5C744EDD0D3BC66581B8E1348E75B5C5" +
		"2D0E41BC71EDAD5B12DDA2280724B7D704BFF2AF04505F65AE496DA86701D36BC9AFB0B1" +
		"99442A9C5C743D97880E89C8CCB34C51890602627924316E79D4415CC1C2ED490A7A6EBB" +
		"4B507181CFF18BB53A6B8F816C15A2EA8667CE59EDBE8F42376001E31981310CA403E083" +
		"28AA97828DC3A86C260819BC8DF72A3E29657CA65B7763A54067958CCD6FD73DF789B306" +
		"A37185C8117F0C86CF9D1C48D102ECA8343F41F86F6084E2E72E6952357D7DC076A02A7C" +
		"EF64724AE634E35712E291A24704D2939717246371B42C11A672FE8FD31DA83FC3D5DE65" +
		"0FB2136A13A0D6229A115EA3758E3AD0810A99944275FA8FECFD2BF1D130B40473F4ABF8" +
		"86485A1E36290DB437B331DB303539F98D298183509D934F1A747AF29BC36BD7CA79E5D4" +
		"0D098EBFE61F400620B5B1AFB81327342AADEC634F1A77DAE793D55A252D391AD155A615" +
		"0AB049CBA0270F07936AC21575BE6FAD53A0DC23F462E377F2C882391BAC1C17C11D18A6" +
		"77C3EFFACC4C6A920596F8654BB4955750BCBC18744375656F0B594D825872BB161A1B7F" +
		"DFE7D01E7A19E02F41AB9D02D1FED47161716172B8D68DB04E57C74053DAC785E9245BCC" +
		"8DCA48C736457EDEB8A075C1C42254E87110CBE4A909421AE6AECECE5D65834739BE6CAC" +
		"51D1023CA25C322B7B3461EC65168CCCF483A2668FB4527BCB312564C4097224DBC38AB3" +
		"97C3A7FD693B29992B9A773C43C0E9E94479F1762C91C367D9A079B13FDC38BD74F209E4" +
		"D543ABF8C9B14CED015599DFAE94723361ACBF6C1C0434DC0EFAF22C61057775F17F36D7" +
		"6FD75D6BFCE7DCE922DCD7585AA33CAE7A6916C4E4AC5F86E4753F8CC798C20205C8C476" +
		"56FBAD7799B6A53DAE5DCB74CDB677FFFA66CBF2873A219413714578D6DA3B61AA29C494" +
		"C2F084BE1FA1C1CC40D1E4A424A4CEC73E455062B6E28C333839570D6FC6C08402A8D39F" +
		"145B97C3AACC6F24702E80F66F5D2FA1530CFF2A07486B3D38D8C9994EE633C2E527AF49" +
		"FBE26F634C6663CF95520E04A76F33E8876826B88887C4FE8FDEB1C50F55C7E7FBC2A507" +
		"7FA029DB53B7CD8FA3576BBC219AE7D7B21518FD94FA187D39D63187BF9F2BF2592F1A7A" +
		"35628137D82E50477FF3406DABFE558A3FD30D4E72D1F523EBF51DF6C7BFD9C85325897A" +
		"7949113F30C9570F3A9FBAF73658430C3B2AFA43BF9D37D5410B5E416C5CF375CF9ADDCE" +
		"CF560E7D636C2D58B89D3E5A446201990EFFC467FFBA1009EE90D0F46BD2D7018AE92CAB" +
		"ECF62130BD7B4A077AF31882A713C73572387533EA249C9A18F0599C06EE216CFC60F749" +
		"8B2A75F3F8143D90A4ABF8651DEFAD600FD332AB09E3D8FAEFA2EC9152EAF6F2BE6B7862" +
		"9022C0231849BE4C13FA08B827EC301150FA380663F737418C8BF0700F4327F58C2256F8" +
		"BA8B61176DFD1ACE6A81C19033E3D678A9CB234F85A5B6372EAF1A1883F5ACED3ADF58B7" +
		"FABFE44D986DBEDA351EA9DE5A841CD523336F986AB8FBBECF1F52B1E87DBB3AC457A743" +
		"FAE899A5BB3D10EAFC4D0808B7FA98C8068093CAE7A0BC2074BAA701273734C28E97CD11" +
		"02FFBCEBB83EBB17C9200BE6DBE58BC87C522E4D24254204FD2EC52C60C1225649C3DEE1" +
		"7012C1CC0D5CDA0B2F0FC4F27274E04ACEDE68BACE92E294B589BE45D74C5377AFEAC718" +
		"2F4B702B5A50B49F1B32BD476483957C664676A819FE6851F07768DA82261C75D53F8F04" +
		"A64291A56E008B11AE09EE73923257EC195020D958F7B6D43ABA268978CB33B150A9C0DE" +
		"CAFBB36291257512CC7F2CB0B5564A0F81EF4686838CDBFE10475520E6EF69047CCA864E" +
		"50C86E9D91FC4EAE741D4BE8AD7B12952B76C3429548169C370A7A5E2DB3FC809B993095" +
		"2EF5AF9CDCCAF74FC13D0DB8D55862858E47E4C6F66FDA9DA423B884DB6ED79D012587F7" +
		"57F0BD974680AD8E"
	msg65Hex = "D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"
	sig65Hex = "BD0D51DB2F225AC6D3DA8F0C2439B0BCDA26EFF7EFA67CFD3C2B98EFA08477A74088DC63" +
		"8126865E493697B6FE360FF9C55B304D15A7474C983C3D8A4E1AB28FF9925CC9073AD986" +
		"D4B53C28B4CC909DC36B9334CC4510AFFDEA9548620923ED2158224AC5CA8FEF19228DBB" +
		"BF12956F5422176E8A474AFBE6EC6551F1FFDE71E86C48B39BE6CA540DBD78B985E89A2F" +
		"7576325E79DCF801585D30DCB3F971C827F4489745D450DF7AE34496C42C7A8778AAC7FD" +
		"DB9740CD3F07A8AFAD1C1471FB9591BBCF37BEAEA10C465ADB4BD7303ED6CA41AD4848CE" +
		"8A5659F7E3D4894AB0E79A0E7206C9FE278AC9CF1F6A3DA6B9FA8E03AFEEE717739CBFEB" +
		"5C26EF3B1C9130C8DD46F9C8E8149DA9B0FE5AA8FD03600F87824A6F2EE8BBCA0EF6D8C3" +
		"8EC526E982100BB8A8974EA91129BF827FE4CCA13D7203D38AC51B2A14025948E5AC0F71" +
		"394EB804C885521EE65EEA303CE30D0FA9626A914F36246A8F55EB2D866B215FC191CB73" +
		"4CC6B4724C8C1562F81E3678D39097871249B86833C6981FF45CEC71339E1C6F38ED1D04" +
		"B6C70C21642D268B5E058F8095101C2339EE5619280F2553308DBCFEF74537DD02722E42" +
		"608FFCA2E8EA8B8A2FECF46948C952D003071792845A07DBCFCC483B594CA9E0A6966449" +
		"8835DA427761E19F9FDF29E5319AA0FBAA7150DE0B1F951D9CC0E1B62DFB0857DB7C2129" +
		"A896D65DCE0ECD3A87FABCC2A4A6FA5811CF6312DC9E3ABFD5ACC116A8A25F45AD3736FD" +
		"B541276732DCD997B1B687BDAC9827A4582B8D3F0877595830E2079DCE9104E1FCFEFD0F" +
		"8225BA9739C30CA7671A05688B55BCA1F9ED968E6F3F2831E3D54E596707BF63FD6AA809" +
		"FE410EC38A17E3F8DE2E050A9E6B81CC386CC229041A7BE15FFC912FC4066A4D2D7FB98A" +
		"F7022840E593C4E599D0309F37B65B85F10541683300779FA41124B19D4032CF8D7AF572" +
		"6D3A08331D7A712DA910903C0A381F616CE5B1085F779486172EA4D7B127692557DD156B" +
		"63B0E445ED8888E446397542E50C9BFE7B728E31388F7743D0F51151D4B4CB7642431ED0" +
		"BAEAE264F4B2D9BAC2D5618338EE092228A251A4F99D4F95D263CAE16FB9A45A51D45BEF" +
		"0F6CAD30547AB4BAA1C6F28E6FF35B195D938514F58FC2B47BEB8C895D213F11035E5FAE" +
		"F85C917D7AA551FDF8D316CC4DE5A159CD4F39E3C118673984147C82BB41089CF0D9B671" +
		"2E899A99CBA5DE33BF33E2C0DA03745031A48A37F7E6A7288790839461F2C58BB5ED9347" +
		"7834B572DCE2DD00DD31B866C2387076037053872D8CF8EB57AE81FDD84823DC69FE0A33" +
		"F599846620AB74E86912759E245332EECFEFAAB9726F8A59256200BE72BC47DC3E0A4E28" +
		"868842935D216334191F32E0630920D8DB05EE62813218A1E1FC5DE96719D08A00FE7D50" +
		"72C8D51B3ED0AB0F9D5B45BBC2D5DD2CC7E6ECCB080D617565119C4B2A4E408A0B18EC96" +
		"9DCDB2BB7D8DE2EEEF3A76A0A5E437C6681AE7A00D54868E0F51EE39616AA29FEB7ABF4A" +
		"3E17865003B781497BA572EDE6EA7A9479FD15C295B79C0384D4D8451043C6F67F2E10D8" +
		"442F0C4E72684D6576FD41BC3756B1A8834082144760C7F609B3665C03F001073CCFEC1E" +
		"B18FB9A61D82A8462D0A86FF80520053C55F2D79502F95EEE9B50F1B95179BEAB6EB1ADC" +
		"4F582A9CA12C31E6F165E064AA9F289DD2A5E12F45E71C98CBC87DBF218926250D1A78DF" +
		"D2B46B1DB4844AC63C5A6960F67A6BF0B270337E629AC04BA47883E52C33246863EB9F54" +
		"BF2DFA5905F057490FE14F993D81EAC50E0D16DD0EB2098D0D1170FBF30892A7BFB45F6C" +
		"6B7E349865CF4313D1572CA41A06C0D5561B0704AF4BCD4CBFF4045C5F76A9A760751F7B" +
		"1432F8049CC9C0496F3E80026E2078CDC7BF54132C84200A4C27B23AAF69E97B25D8CBAD" +
		"A6F5C82748D73F8CEE44980B909EB0C11EB49FCEA972552BF5BE540DD9467EC81D709905" +
		"62DC558C00CFF68DB80F3D2BBE61D7E154A2D5A4166E86546D8A82886E1CFA28CE2D8BF5" +
		"7D67D9B6CE32D451F9B2B4D73474C299C64FDD8D2AE15EAFC3F88179B8B364FE16B51E7B" +
		"6C4DB47D796E159546BD409DD72879234578875C7940E057FB9508DDD9754D130F5CC3E3" +
		"2D82104DBCE1BA883FBC0C9AB9072A1A2771B0EA1152682D182D537EEEABE3F79C531A26" +
		"E236AEF6479D5A7817D00723D0183E4A1A671C3285BAE7793D7FF982A6B90F7D38E40F76" +
		"3EDC401F2BD0618D3E305257CFADD3CCFED8DD3FD03CDBB533976FA353ABE73503EF8360" +
		"964C2CA78888B4E67B0EEA68D35E64A840D136A7F0CA41CBBC52543BE45CA846F0213EEA" +
		"90D932AB3A6902795B0B4FAC28C838224309E94782FA315BFBB9A535F3763FA9C3C95FFA" +
		"3FFDA9C486678F7905A3637605A6929F234B9B04BDC729E14581888848930DF0D77FB1DB" +
		"65D75F292E0EC78FFF3352ECF99D87E0B6FFC78F5B9CB423FCCE606D74D35D115A418EEE" +
		"AE012026691B82D5B0262A1DD137ABF192683173A5615A3298A2224280C405EEE6094ADD" +
		"0E1ACEE74204BC0F8170221621A71743084A072FDF03293D8FD7778E8E3282DC49A1A950" +
		"404CE827C281E1F57E9DFA1F1156726DFCA3560F5C909987D6D79E831166155D5AAEE8F1" +
		"ED382863195ED48EA6924D7A119EA99756434092F08E217804EB4943E56A42CC7AC5CDFA" +
		"7CACE562FAC86AAF3BB5C3CF6F6DC35036B388E9EC8BE2272C2D6CA425FF23E6EF787833" +
		"2042B120246271B93F87C463434921D0BF6A105A2C7E473B3C5E4BC5828403C130005B2E" +
		"EDB7C161010A7A782AF3EA91700A7610DDA532DAC61DCA768B51541D2F6213B9C5047CA2" +
		"AC0E1DDA275EFB58359B5AE203706BBCB1B2DB3ED8896C3721B51865A6F9B4B8949FAB4F" +
		"3301AE7CBDC540F0B04FD6E27BE48748DA228DAE22353DA7CA1C464E70FB78960491279E" +
		"827128BEF241C764061A5AD103EE62B26AE08066C5F20B807883C8E8A3144B7968F23262" +
		"7440154FED536DCC09DC9E33BB7BCDAED850F0435E1B9D943F79640BA06F21F99A1D8999" +
		"7BC5529D1E69095DE36958B8F186C12007DAF19115B0F971DFACB126280E1C4B956C458F" +
		"9AD2EDF2226A696685A3DEACE620DBAD643B4B2E31911F53BBCC1E712B83DE8687D4956E" +
		"BE1A30CF4D7E86DBE8B6E28DD6AF59BF6E83E25D9B67458ABE922181C4BFA5E5D047A779" +
		"9D8F117411DA633096CE2ABF19C5317C545835B06A54759497605A0265A0396C4F069F7A" +
		"AF9E677140679A265893780B0F4ACA2E48010346CDA16356E6D69F48FBD6E9763E1EAF57" +
		"6008BD2EDCCA2DF8808989D801F687EFC97EBD1C0FAA8555664BDD49E39B38565480D7DE" +
		"0BB51E1CC5341DBF12DA73B5AA7DF954B5569272A7A3EA3AD45D8F65F718007A0C35AE3C" +
		"7206E14AE7033E4DCE999F232BBB488AEFF090A1D160B10847B134FA82867114C4EFB7CC" +
		"83DF601108E61457F7242FB159B0840D7711C0C50DEDBDDF346BFBA7C7EFCA4068B35B93" +
		"FF81054115AE59DE3C55BBA020AD66893B88AE491F8F6BD45BDB0D506D15E050B26BDD02" +
		"42F0EEC3092830E3F35D59A4B94B7A41A993F44DF9199EE6B084681D554AFD3970DD410E" +
		"748F4A95F3F5A3B2827F1C587B563FF7F0D7C47AF3B9F72B8AD6A46C2CB178929F80C185" +
		"2AD8247769BD4FEE274A0A07B20137CA67674E91779D9C6424F06E78A8BAC807C31CBB46" +
		"77E9CC7D8755997BD19DBF053F1EB7DD6DC3875E667088B0501FDDBAB90C6A4C215E28B1" +
		"7DB87B0F4423C6108813AC993F69CD20953E0C6B85E308F20F1855F5993FB269159F2EE5" +
		"D87316A0B744CD6530BFAF581C7FBAFD20689B702BDD4F907CD9D5ED768FAB06CD625B17" +
		"1D7159112E2446F8B6B2FD3B89F43D6C42B5120CFC98AE2762D241C41D32DFF80F714711" +
		"9FBA9900689E1919EAD74C77F27C046B513FE143884A439F1E8399CF97C7E83F3BA585C5" +
		"A0117251EFB5AFF33974D5B0FDBD61B62CA5692983643788AC31010E70E6909BE8757F6B" +
		"D2E721BAC6790F8DCA7D1AFCDA291F1DA1669E8906F4880E0E1BDC2608A0DF671BA401C1" +
		"78A53AA6E1B2D6C90D2769E4230B60E9FF10EE38A1532090B3D5076D1D320697F4AC06FC" +
		"8574136373FDF90D6872190E26F5311BAF686A95F47EF7A31F8A6AAF0196D3CCED25D5A5" +
		"49FE618D02F3C531FECF1C6770BE5B43FFC299519B7AA701BED350A09AF45B9268D8D5D8" +
		"1E8B962303C1F8E4BF15F5DE14A85312EB1C9511DF3E687CA14081754A2958324B4E5BAC" +
		"035C91240F01D7719DAAE546ED56885F1F393DF95690C20618AAE3229C6488AF7820C3E8" +
		"B421957CCF4F31A5173B7282FB972F7981AE53F73F2AE5747B608FB05F01888E80C1C6CA" +
		"031D52E573FBCDF986471D038EE3C6E0814E24E8DF75BDBAE63F2909B47D9401107439A6" +
		"B022C897763194687110D50779A9ACA6231B04D587A87CAADE5E4E91B7BCF43B2E469F52" +
		"DBF19AB1D180F477D5DF2E45ED2609638E22E4F5143BB0E733F16AD183153C8460E9D0A8" +
		"21C9AE4AD7DB358B18E91A9022A26283F553D722F4D37B3B9EA7E5F684A1395C72EAF261" +
		"50960A318B8901630E1A657479A2B1F7181A1C215678F3626BB7E2FD0F36498497A20F2D" +
		"3C467E803F697DA800000000000000000000000000000000000000080F141A2024"

	privKey87Hex = "7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2D"
	pubKey87Hex  = "903EFBF16CD1F779825106F76DE12DF49CA4371B57117480702A1D94DD9C2042BDDA0535" +
		"9144230762A55D09AAF6961245E21B0D413DC2F39CF995327C6A1D52607BD9C3ADDF70D0" +
		"56361D8EB86C4B60FB7E0DE5638E4255454CD32EB48653F6A9047247233284953DA6D5F6" +
		"5AF1B59421673F6F9E89B58D483C6A9D3FC4EAC36CC3E489CA243F17DBCF0686B8B4DCC4" +
		"A37078B7A8B28218777C5C223ABA3123EAACD83CE2ED91ADA7EE0EFA23179F4457903417" +
		"EDA5350C4F4BD856DE0BC419C91B76E7DE9074C8EB4434D6055D80AC55BA276427FE3C84" +
		"4EC42BBD37EBC6CB142C6C1755F02F7F0C94631C987EC447060898B578144950E77CC51D" +
		"9797DF07025C8393ECB565C32EADD3179C696CB6AB5DE99B8FCB623E8C59D836AE3D4E87" +
		"9CFF4C4849880F0FBB293E7E637D3897D47CAA894656D58434244593D72A9781FF045A40" +
		"5F9C8886D1C2B828467A9BC28C4E29AECE6536ABF539B02AB03C876D899376CCDDA5C1AB" +
		"C4D3B2AAF3C5B3C7AD1956FCDB37F691E3E3DBB43EA967E733EC9E2D06D5A0E9FD67AF30" +
		"20CBAE5FCD7490E44F5E2646245FB1B92C93BFD6945093246D490A1A0FCDDD6D46BC4FA1" +
		"1137AA673D562488FA72CFB7FD210D3B3F04794415826861E87C50FD9B297F0EBE32153B" +
		"959D2BA684AA978827BEBF6B825C8C283388DE6237BA4B51A0D47F01C57951809B9592C9" +
		"35C9ACD64F45D08D5207BA365CA2AF7908C7791A4ECB8C20EFDED66EA640860293542479" +
		"7912E1363CB725C42DEEC98730FA99F17AF4DBAA825159164878F5B97FFB8959160EF304" +
		"E5E1A10D7F8671454B81081D7E24A75922EAAC49DD67C0CAAC7E24D3F914ED64FE618E26" +
		"860C6BE09A6BA56100687B3F0A61EAD9D55C984107B1DB88A1901ABFB93B0C3556E4A360" +
		"1E08BAE9BABAFB177D61702E0E8A357A2E760EDD39CF7A3C601C022C629607BEA771E408" +
		"BED8C96788200F16F3F76F9FB89B4F04389D40B76FF720CE478BACD77E659359D3803BAE" +
		"4BE439FD4A212B38E169BC1A1CF9594FEDF4A33ED7DA7B3E1D853D055D45C85B817805D2" +
		"5B59B52879B1EB7D59B723D05AFBF9F62FB1384A12748B0965FEAF5CCC5F45162F173836" +
		"D87B25907C262AA247C198E7EDFE7A472BC6553843E14C39E70DC993E566F0C339108FDF" +
		"32A7C9C9186A09BD5773B3D3393CAF8F8D3CCC2EDB7BA08FFA76C918669560CC170F69CA" +
		"41614ABFE6D230AC167A8F74F6664A23179580796EC0C01269BA2FEF895B36EC666E750D" +
		"CE0F76BB411867EC5152EF5B1A1AE2A857D791147EC9BF50D4B1E93562812787C7CD07B8" +
		"ED8CCBC294EC0721775C69731B3B471BA1621CD5BDFD11D5CA1D38EAD2A5B565D617A84D" +
		"08FF1F4AD5BEE0470D09B67C8D24C9018EB13205E6C86049B50C5DE2C52345E015732CF2" +
		"CE1DA9E5DF6CF0F54256B4D1D35E7193AFAACF616E28E761D977ABF2A54A3FE5D2823A27" +
		"5DCA6360394F0A7879AB61871BB8F15C9BF1D8990DD256FB7F07C90541FB2AF3C264E24C" +
		"8DC24BA47F6E23C9C17BA3162CCE979C063A47841A3D264CB8489082B3B1266539ABF7BB" +
		"6D6C277064980799793656E1F56906BA4541C19A8969CAE9FB98EE76500A895DF493FA7A" +
		"A4D8C4CF2F6AC554AEE05490C1CC888A8D9F30F477EF76DDC191794F0E92D3FEADE9B09B" +
		"1DE64ED0EBA2BFC82D6BFC693A48205310D32BDDBDD48333AC81DB32B404163E6A835A5D" +
		"CC3308AA0936F39E66CFD9173437B00BAE28D6D4DEFC2DDAD001E2A6E782BDEFAB164A21" +
		"4F36E95C307CA141A1F38D5EFA943779E9D01A72100F5DE76A072074286B5C6739B805EE" +
		"EFBA5639F2EE0880265ED091E4A2DEC230CF7453F4BDEC313E16297338A3E3F6E03C8FB1" +
		"208909A46DAD667D14BCB66F9D21573EFCBD3A4B2D8196C94EECC453D943C8B27D3E2BF9" +
		"B7DEFC2D00EFA3FD131BB48170A263A76366B78BBCC0D807CB0DCA4DAA9948C8240B537E" +
		"CC28FEFC3AB60D88A3486A5FC15C4BC6EC099E17D3A6B7B2761EA86980189E0E606BC0B1" +
		"E971532E627AC167726902A9D44C50BE24FFC34212B54DC596064E34B9821E6EA5A63892" +
		"F187901691F516649E7B01748AF1867A42A63BAB54BF551668D0825E64773752449C64EC" +
		"20842E5B8C6760D3379137EB9B5CAAAF469474AA9BB3C1F1A5C257363EB27BE4C7BC5C89" +
		"0F5D9532975051F2C4D62D14C0024289F240A6ABDE67C0896DE2EBC84FCFE99CEF7D15F7" +
		"9B221617D385782F60564B0B5911EE2D1BE5459058A37C578D0348D1C6E5976DED66B6BD" +
		"26D5ED78AFC59561BC28C75FA4B5048AA59D7D7010E22293A14D27B7B6F2ED3B8E5974BE" +
		"2E8E46850E30737896FA0A2104EF31ECB24AE8B16FB090AAF578811A60D864711B8BE1CB" +
		"538F69A3AF67EF47B81D50F07DDAFB394373F8C8678D938E618184955D14EAB88D715E1C" +
		"D22E33AAA7027378C392D76F458463F28A7F365EE708EEFEEFDDB261D0EC1F44EEF0E008" +
		"4DDDFCD7DD4F28019D9184091C6E2FF0DCEA261DA0EE746AB6EA802F63C1C374675B52B3" +
		"935B937EB7375EA28E3B5198C8FE2C9A677BE319933D981A19505E557A2ED6E007110F0D" +
		"95689ED23F62F20525E0029E4789933136B6CD3644F4D63B002A0B5942EAB5FF7B858B40" +
		"DC120D78BAE089A65EE5C7128DB3841DF863F476AC15029EC0147A0596D2293D1B5F48B1" +
		"3071822E2E8E9F525FFF083732BA87719FE92F6B264D9950458BD2C499E45AF0C6179B0F" +
		"116210844306EC289C478FA72F76A6AC46ACC55A32C19B2827127FA1A6D6F36B1EF50CE6" +
		"7A458643CAAF9B8A9FE3F28EBB7896520D14827F64CA7D6EFD9B8599EDE0D32F97483875" +
		"69ABB52028E042EFC659AEDE4EF4EE4B85FFCD17455A522ADF712C6675F46A3DBF341E6F" +
		"C748CC19CE8306C1E3BB762F69B171446D36E63A299D0D68B88ECEE3D7FA919BF402CA3E" +
		"BD46FAD001BC250C8177CD43AEEF01D32417303B65728FD25DCEB9F1289815C3132EC1E5" +
		"7A376F1C19D6901C398C58A3D7DA3AE23C399EB71FA31A86D1CDA4940B624D28AC93DA1E" +
		"9FAC52026C3A110250B5E95F78229059AEB9703377671E47A09496F1DC333BE19C537514" +
		"AB5255A27838CB039CB7817D35C387F3A19E21437EE1CDD2C7EF58830284EAF677DCE2D2" +
		"1D4B1ED54E2B2B15977A983CF939A9F5AC5598DD73E50A43CDB6BD4CA9F08B78CD9C96CE" +
		"D06554DB1CF4A6749FD50B062C702A6A2EE9F6102D7E848254593E430EC9A659E0104602" +
		"050B49B70C4F182327F3EBBC4214FA6BD034E2222CA012B3BC288413F6ECE618EAF3ACF1" +
		"B0D9AA94A102DA9B56329F4C808AC33D35AF54E6D4C1D12E60734EB0289F1674255AD4FA" +
		"CA9644C36388E65C1DA898E4CD6531E89592E1E57BB2988D5788EBE1B013283DDDFA346C" +
		"DA5B224F5F8BEFFAC5CA521BC546AA3F1EECB254C597314657DDA91727BA42929B3993C3" +
		"C44ED3CE00AA1AF9B00CF9EEFD7530ACF29C50BD0706620372424F58BFB356D28EF5A8D9" +
		"0403C52D62DD2F92A19B75E6C46CB4EAC77A9102A6DCBB1DCEA05A28688B94ED3966E956" +
		"4519580803795F038255CCF0AB91762898942AFA38E4BF7839B3DEC19D2444D5237212E1" +
		"5A491D1F5636D41D0CC3751D96D856F1CD4BF2A3FE1AE8168B2475D11051EB1980C39FE1"
	msg87Hex = "D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"
	sig87Hex = "A8DF889472D431F08DC5A3A28166AA9DD9AC5A9CF18B7D3D91B27B68E26DE5" +
		"2C194CE98A34507E30D20E587625BEEF61817B207D678E7D5BF006E681556C2D8F01AF7E" +
		"ABD9E86484296D99D471CE69D8DADEEF53B2B84E53B0949D7E0B13E0F7564E6FB2673F33" +
		"D3FC8689E7FD3F23C27334A3A6A7DA3E7EAFF481B2C3C48D22AFA40AC10D7DBB45575D30" +
		"89DC5B6041D0658F2F6D7083A1F875F07FB5CAC47273B3300371B7FEA083CC1C3123B8AB" +
		"5D58907481C53636FFC5F3232FAE529CB42A4CEB8DC59219C9B7854A3AEAC6E0774DAD6B" +
		"B16A7F2630F0EB003DF02CA028CFCE3F3DB170F3A23A1103718F559538C4E7E2E1DF0E10" +
		"326C164571E27D59162D10ACE2FBF0DF367E50F3A21A5B020A65F4F48A247C218A147DBC" +
		"A59E203D462E01F18399A3B53E667461AC1213A6B9424A2B053C3E8243A79B1AFE6D4BD8" +
		"2AEBDB15B4FE968A2CD207FFE48E5D256F1B61D75A14EFB6AD8BD299216B988BF964A569" +
		"E2A8D07B9FB91E16624673B5EC8D672A430CB683F3E58E1633B377245FBEA9D1F5AFB78E" +
		"2A516FEA762D3DA847A61346BEE2E0E6D77FFC0328A01D41C2C395BAAD5953D037DB755D" +
		"57F9F82F7C8A0E9A586F0C5ADABF965D9FEA1BAAF14D9179A4D385DD9BA0DB6F32672F2D" +
		"D0C9A0A738CCA27CB864B8E9706C599335C3DC168B84277E3AD532C4730C799962093EB3" +
		"E2D36A6DED42495CFDF8467C48DB277AD977777D2C0EDD61D76777453A9FE173FF7250E8" +
		"FC2200E45D5F276D5B7CCB2385678359B2ED5A1EEB08506B52DE9BD461BA2041D1D556CF" +
		"5265DBA97050BB58C34A846F53C6EE20ADFBC723D3AF2D6E84A767060FC309418B3A7DFF" +
		"86A2C0041B04FDD12BA3BBA0583A4B7A35334AFD0451D69F34F10AF727184EC0F59D0CC0" +
		"88811DFCC180060F2D10CC4467CAF54F4F068A756416E40708274924C42D0003E9701AF0" +
		"BF5BEC2ED18B441CB23F8FE76BC0862AC3AD5C7DC06153C2CBBA9A9FA7C50CCB2AC162AB" +
		"0780DDD93C4C0FED5CFF981287B0A8FCCC6DF141EDD94969D27EB491F808B30A20CD9B93" +
		"4AD69DC7BBB685A7D4C9688D837DE438D7E040ACDD28C7ADF3BD577BFD95BE0F1F2A9BE0" +
		"C79D76EB6EBA8F883B779A68312D4E1BB3A79905C49ED0750310324526BC7668461279B7" +
		"E8EEF56ADE2F818B84960614B53380079EBD3A9146FF1B57423EE7B946ABB23B6AC2C6AD" +
		"B95EDF412D041EFB418737F57CAF04F5A4F90FF810DEDEC8A9083ADB44FE9F7766C18FCA" +
		"8144BD5F52551B003563DD0D6B4CE4B730896905F66FA7941F1E88B6EA74BFBB6577DDDF" +
		"1796C49B7B8489D4C4AB46BA3B4B85BF9809BD2569281C5F24F7EF9E244F08E3CBDA3061" +
		"7DC7A9E8C84C5E5294D5D53356C6FCEEAB677E711B9FFAFC400C3F27548007C4A15BEC89" +
		"9D8011930C638C244661B533C1C2A84E1B7C46328500CDEF3A73B045E6510D890DEC59E9" +
		"A6A252788AF5A4A9050A5F98C864406E8A0E80AD2E9D91D178782BB71D60596C68A5283E" +
		"BFEC1B752944916784EBF60C85661EA4540D558AEEF9DD9D29E92250063CA95FDD962E5A" +
		"AAF717187FF20125FBF9EDB8DD000A73F90F04118B2EB01A914F228A1A370DCF174A5F5C" +
		"C4BAFC85230CDC02F6BE71BD1FBBB43D6B4A696E8880D5E6431595CEDF320AD30BB01024" +
		"1131BEAAB242EADB178D46B277DDC0EF378B72B4F4F19F9CFD7FE7BD49FE6EE6F81FE482" +
		"4E1555D9D16352D5E596CF893A84EEFA8DD5D70C196B3223674845B0B7F2A49BD4A79985" +
		"253C5EB65447DB0338059B99C0FD643055D9D8F6CA1223DD2726D17F689CC147F8098CDD" +
		"FBAB9241AD8EE87F9CDC07707B4ACCA17CE40B6FCEB22DFAA960B41972F43D3FFBB0F08F" +
		"BA95C1CBE6726B858F41AE2410FB0B83EFBC9E003C6E031271051257E6A0826ED4DE3C5C" +
		"7BB175FDCB2F585513772996F9BE130F6DD636E8E99EF09D8772EA84024CD1274F7567C7" +
		"743A067656430A0BB2DCE44C2020D21298DCD04BC48A6FDAF97F0EF988CBFF4E2344CB5F" +
		"4194F84F2EA2A0E16959EB6CF8751C2B0D5DB52AA8F41526058118A5EEEC802ECC11B88D" +
		"3BC5C92FEB99F754E48ECF49F8FC39036D1B49706B91B663523A5AEDAC44B06301D35949" +
		"548D008C0EBA84B711733254EE72A6B40228A9699B6C5E3A63C236B0941CFBC3DDBB39AC" +
		"BE3E23523B7E2D9686C46652D7E4D929F5975251DEF9328FC14CA119865ADC0E916DA16C" +
		"D0391335AAE5DF649B359AA4591D986AF5010C1AC9667A309F3CC79A19FB6AA020E72DF5" +
		"0C1AE2CE60052736A0BDD6356FCB3730E747304A0D0E7A7B59C3256F12576B6BBC446150" +
		"5D2B0E09DA0A58D87E8CBCA13D34F424DAE99029A24928B3CE8DD9C794B61FA8D4848FB4" +
		"9274022B3B70654B08B1F88B6D7DA5046E667F92E41F8170FB05A2B536A07DA7F41BC4CB" +
		"1AC3B0EB4D3AF505E5CC2B4D98E4D9C43021F8FEC85428C2E475E5AE8ECF578BDEB4DD5E" +
		"CEB0042874B03C5F7932AA7F2F1447A04D72034575477CF165AC5E93424AE66D0A04262B" +
		"308F546C226A2CD7545DB34EB8A98817D4414918FB634FC9D947A637A15C26DCFD5BC60B" +
		"4D44F1A0B57759BF882BC33183689B979D64396D96BA3B75A6D6A7DE95784A6DFDEB310F" +
		"2F21AC424E76BDCE4810774831E4D2E14A28473D2EB4120830E71A52975BA56C84198CC2" +
		"58C7748B936A0277138AB8CA6E62B29E80C30ABC0BC984D3DA6869C035FB258A2513D695" +
		"974EE647593D4DBBB8A6ECC05C935FE634BA612B5D7D546CCC446F2F354E4257ED524FB3" +
		"5C42EF6221BE1757B3BC077BF64C93F0C443DF81EEA4B323006E557D4240708513086E23" +
		"081F0C13DA054B47D62BD82C79BC17F2C488A386CC2456270DFD0FF3D3724A181EB9ECBF" +
		"CFCFF63D6AB3D590099E3444E49FF7AF6A79D9C2B112BBCBE08A05DDE98F750BC0AB5972" +
		"F523297F5604E35DFD5AD0B57950D4126D2BB10A1840A9C5ED7CA5F9C1A08F29E7771281" +
		"2F75138F60DCAD014023B97301B53B04B870080CA3E2CFDC29C88ECABAE877D6B6460BE7" +
		"2F04DE84AC78ED50268D977B1B56B4AD7753BFF23CBB6547EF7F997BAA3212158FA5DF1F" +
		"C9001D7C7D56CA8A6FF42CBD7FD77CAE658FC5408AD8C255D11295D0E05763F4EFBC1087" +
		"35402EE9CCA174804E1DB90EA18C88ADBA36F61647E7871EF1203AB929E91CF257DF81F8" +
		"2F4C1954C5D76AFA01A1A68127AEE1989AF4B2F9AFBA67596443F60F2C4249036E96AE6F" +
		"E2B383E90BC360F8F7C1461A9F24FB0DC8CE57D2E7BB543E3F78C047E0F12D781086A782" +
		"DD2D9B133597FBBF9AC5A444AB3C3523E176E97D5F6D82183B4252FA35DB1D6C1A7DC566" +
		"B1007F8E889AADBA9E51D0FA662F10AD61B713378D2F22C2E7AB01B9B04C2DFA6748E523" +
		"F01B7EF497439E24D9D0071FAC7676FDE2B56DCE2394E2CBC9CFF55DA7D23FFE0D6581D3" +
		"E97BB2487ADD9B957F1DB9D399BF84E1564A0C92EBAAC332CE2EBC291E8B5FD0F3734347" +
		"B1D8B8C940D3B438A265CDF36AD96DBF6254229B96FDD2CD585C1A7686055F8337395A92" +
		"98D94FC8348F73E41DC9870F1C8F325113579CE0FBB729EA270874395B81F23205D26D2D" +
		"A922E997C509AC213411B667D06DC4EE0A699B8D1722AF1903C6927EEBAAC3AE2CCF70A4" +
		"47C8BB7F48B3C7198EE933D01D560AAF42EC7468EA81AB8559BB013844103CBA500D1540" +
		"393BFB911A5BD902D06B3B4BC0F7DC675BC281E5E1E2AC0BC4B762AD18D4631BB3ACA3DB" +
		"02CCC5D56432315D0E3FD1C4C8EEF48F9B534C1B7FE0E38000C1AA0D3D49A68BE281BFF3" +
		"C1DC4923EE62B44403221DB2D456B2D078394483159197F43AD832C75606E0576FE0268A" +
		"0FEEE7646A6FC156D34DE3C8B13A72EF26E33E7B6A41B567AB1CABC3062A8EA10AABE1FF" +
		"EBA682E1B4AEBA5DCCBDDEFF105F11A35AE84B47B748923DC7538576712F1545A702AD7A" +
		"7B6EF7DA967C43278CF4D53E09D377F3CD93624B33ADD34F51292E98DA4A8729557F7A31" +
		"129057EEF37B89A88B08285D749E209D1EBE4BF97E06F8A46EEBFC3A31C9FB0B0054B1BF" +
		"AA47281FBF312B59E8A4D8157595F8EFA1E80350EB9AC16E1F300872B39F5FA42C742DD6" +
		"95717078C3886F5CC2A93236FF51DADC1DEBE783FF7C287B7F4D3E9ED7115DC7CD44488C" +
		"29E982D65D1CE41BA065AA948C52B4CBEC24CC3E3D6E8139ECA8003F609F0598DAA983E5" +
		"360187640BA411D9D5ED3AB8C790AE74887512CA90B0A96FD0CF45B4CA2F6DE0E382C225" +
		"99CD2FFDEE6FD5AECA0A2F29AAF069C61272F70DF4A0D34AD3D2B3475CAC8A832713465D" +
		"C9DE904F26D0217115FB081BA0BC2A10C2455FD977674145A33BDFEDDB4E4FB715236818" +
		"F02A7C13C1197B97C86F103186BF5159701A5158A4E49DD24188D3BAB5137BE43FF6C594" +
		"B976C7A7F8C3C92A6410B0A6E748BD172B5C8EF327BC9A8BE9E379CFE12A64E40C97069C" +
		"ABECC57ABCDB0C96FCEE703566141138B35CD2295607384402EA4C1B9A6591DD6D3C3031" +
		"97BAF0B78F2DA9FF52B64D0C0263E9D4EB5FD09AD3E35A775B14C54D4D6433F1DBAC9C17" +
		"2E330508400710B783CBF8E96BD0B8262415527C37F408CA3B761237A08602225E8EF286" +
		"E35B6B08C71240B50D2185BCBB47D75E3E73B2AA68218D53BA811AD506BC99D71D3B6B2D" +
		"35A0A9E34B7ACBA12948C08790107505B054B4A828C26974056EDE75C1BAAED177A29ADA" +
		"44600B6BDABBA2BB0E23E3B3CCFF462143A90144D4BBE6968293EE04171798FCCF47CA45" +
		"B5695C26DF18FB2745817BC249757E3613E8D771153D65DE7B4B4B1594A0A9D30C907ABB" +
		"F7DDAAB3B421A0E805702B89C4C60A0E4ADDC01C5A51843DB066EC5F53D4BB2D70359B23" +
		"74E9D23DE6A374BC8D4E01F4DB24A1D455E8FEC641B8C7F7E82B22C0F3C195C9E87C6BF2" +
		"4DCE92F3DEF54AE5B549CE8F095C09ACB01B0F6619CC4311444E3E4A07B9D8DD6DC9ACA1" +
		"5E3DF12CCBD315855240BCE7AA6C1BE58069FECA1A789C327ECBA288AA5C52202F663305" +
		"A405E759AB0E8DECE984EBECD93D0BD64947339C139787362B7C1EE02640FFBD81A9EB6C" +
		"90E1400A7033C35CAB822CBACBF6F3397C1195B1C6B05E9447F638E97143E0DBF1492349" +
		"7154E20028C282A09F006DB42C61E8AB94875C22940E9ED850FA633F640F57637871F1A8" +
		"90BA3E5635828ECF5F2BFD3F540062CF45E8727D053F56D704B73F37E1B99D4EEC508285" +
		"0838AF09FE53DEC2C9E5607B095C49254E0EE2EEF40B05C677F5F9A70A424D1D67F1CAD1" +
		"6293F6485F149D2BE1A699A37434246E2D9E4F3A9BEEAD5E73AEED5A5A01E4A931CB60E5" +
		"D3DE433A17E12615EFA06D6B7ECF8487025574A09E077AA20832E2EA292C0249FBF5C3F7" +
		"9C4E01E90FD18741786A33314835EAAD8C46DD2DD1380DB32ABF3DBB5B0F0883A34AA8B2" +
		"3B4404432B6D2893BE1C47A71454F9E429F918FC87CC1A0D02CB29F604937AFBDCDEE937" +
		"AA67501E9BF113AB08518501865D6C53BE1E4759A9784C55147B5A83AA764B67913D52CE" +
		"C438E0F3AF142F82A3FD6B9247611070416FE14F51D65E54D34AAD84796497B057B7A45F" +
		"C59EEF8D74BA4EE47E4E6AE426AE060D251928D9E98132944ABE1FAE99AC1218A643A982" +
		"773ED242B342892F1660024BD5848B52425932A67395732DB81A1DE2750869555374D493" +
		"0CAC5ED2EBFDE371BB562F1D29E69B928BCDDCA10B307099212261142823357BBCCB0E26" +
		"C6503DA192135EE95FFFD4EABBECE9E9DEEA4E3165F178B3BB65486EC2D31EC54B93C0FC" +
		"5831743BD11E8464DBE413A09CF83A805CD3DE2E2198C66F27A9ED21974FDBAEA8D12EFF" +
		"499CA8ABC2B437BDF6BD7A11C33F07143A52D21B72C9AF1C001FE8857CDAE2E3D90E070F" +
		"4CEF17058E3171F21983D91B77D3A86C93289B4D4362D67C2B6942913BEF11BDEC221933" +
		"31AE578B4C6826552A393CD07D69A1F0075D7D2C2683D8048582C46A3D2F52F1B8916534" +
		"E2F565CD0C848AA469617D08ED4B31C6310D37AE89F9B69A56603B9C0B6E2AB97D0F9EF5" +
		"989875D5ABE0B3048AF3A78265827C5DE2933072283B1BBBFFA7BBDB04371F5B88634ED9" +
		"184D3D68EB1E5124D4D7E0517A4F92CF638DEAF4910BBFAF5F58DB78A5AA5F6C0D1DD48F" +
		"AD3E2B9D8C2491F304468F8249ED5AB8F46899F6E9D976FA35FDDA90FE5399E130313CDA" +
		"A4577FB00E9ABA9570C894D77725ED11DFABB1DBB930008FF9A1042D3CA268F8B00F5F4C" +
		"2DC0DF84ED00EEBA642D1606F3826CB99AC5F7EB197C9244A7937799D66DFB211103FBE7" +
		"69546EF8675FDE9D8D01BD790C3BF43775F950CE131966F6819881F976D764DB5EC3902F" +
		"D645F8234FD4423043C2D2FBFB1478FE4D8C2877866F6D7FD88F4EEE5A9BB9783B25C0B4" +
		"0C91532ABC1207B251AD86751A2D3298A3EB1A9FAAFA182445519DAAACBF19666AA6BDC0" +
		"E2F808BCD0E3F4FC495E8CACCFD2DFEBF1F7F908445D96B1B4C5C91D637175BC00000000" +
		"00000000000000000000000000000000050911191F2A3237"
)

func TestNewPublicKeyFails(t *testing.T) {
	for _, tc := range []struct {
		inst    mldsa.Instance
		privHex string
	}{
		{
			mldsa.MLDSA65,
			privKey65Hex,
		},
		{
			mldsa.MLDSA87,
			privKey87Hex,
		},
	} {
		t.Run(fmt.Sprintf("%s", tc.inst), func(t *testing.T) {
			tinkParams, err := mldsa.NewParameters(tc.inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			noPrefixParams, err := mldsa.NewParameters(tc.inst, mldsa.VariantNoPrefix)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantNoPrefix, err)
			}
			privKeyBytes, err := hex.DecodeString(tc.privHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(inst.privHex) err = %v, want nil", err)
			}
			for _, tc := range []struct {
				name          string
				params        *mldsa.Parameters
				keyBytes      []byte
				idRequirement uint32
			}{
				{
					name:          "nil key bytes",
					params:        tinkParams,
					keyBytes:      nil,
					idRequirement: 123,
				},
				{
					name:          "invalid key bytes size",
					params:        tinkParams,
					keyBytes:      []byte("123"),
					idRequirement: 123,
				},
				{
					name:          "invalid ID requirement",
					params:        noPrefixParams,
					keyBytes:      privKeyBytes,
					idRequirement: 123,
				},
				{
					name:          "invalid params",
					params:        &mldsa.Parameters{},
					keyBytes:      privKeyBytes,
					idRequirement: 123,
				},
			} {
				t.Run(tc.name, func(t *testing.T) {
					if _, err := mldsa.NewPublicKey(tc.keyBytes, tc.idRequirement, tc.params); err == nil {
						t.Errorf("mldsa.NewPublicKey(%v, %v, %v) err = nil, want error", tc.keyBytes, tc.idRequirement, tc.params)
					}
				})
			}
		})
	}
}

func TestPublicKey(t *testing.T) {
	for _, tc := range []struct {
		name             string
		instance         mldsa.Instance
		variant          mldsa.Variant
		keyHex           string
		idRequirement    uint32
		wantOutputPrefix []byte
	}{
		{
			name:             "tink ML-DSA-65",
			instance:         mldsa.MLDSA65,
			variant:          mldsa.VariantTink,
			keyHex:           pubKey65Hex,
			idRequirement:    uint32(0x01020304),
			wantOutputPrefix: []byte{cryptofmt.TinkStartByte, 0x01, 0x02, 0x03, 0x04},
		},
		{
			name:             "tink ML-DSA-87",
			instance:         mldsa.MLDSA87,
			variant:          mldsa.VariantTink,
			keyHex:           pubKey87Hex,
			idRequirement:    uint32(0x01020304),
			wantOutputPrefix: []byte{cryptofmt.TinkStartByte, 0x01, 0x02, 0x03, 0x04},
		},
		{
			name:             "no prefix ML-DSA-65",
			instance:         mldsa.MLDSA65,
			variant:          mldsa.VariantNoPrefix,
			keyHex:           pubKey65Hex,
			idRequirement:    0,
			wantOutputPrefix: nil,
		},
		{
			name:             "no prefix ML-DSA-87",
			instance:         mldsa.MLDSA87,
			variant:          mldsa.VariantNoPrefix,
			keyHex:           pubKey87Hex,
			idRequirement:    0,
			wantOutputPrefix: nil,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			keyBytes, err := hex.DecodeString(tc.keyHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(pubKeyHex) err = %v, want nil", err)
			}
			params, err := mldsa.NewParameters(tc.instance, tc.variant)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", tc.variant, err)
			}
			pubKey, err := mldsa.NewPublicKey(keyBytes, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", keyBytes, tc.idRequirement, params, err)
			}
			if got := pubKey.OutputPrefix(); !bytes.Equal(got, tc.wantOutputPrefix) {
				t.Errorf("params.OutputPrefix() = %v, want %v", got, tc.wantOutputPrefix)
			}
			gotIDRequrement, gotRequired := pubKey.IDRequirement()
			if got, want := gotRequired, params.HasIDRequirement(); got != want {
				t.Errorf("params.IDRequirement() = %v, want %v", got, want)
			}
			if got, want := gotIDRequrement, tc.idRequirement; got != want {
				t.Errorf("params.IDRequirement() = %v, want %v", got, want)
			}

			otherPubKey, err := mldsa.NewPublicKey(keyBytes, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", keyBytes, tc.idRequirement, params, err)
			}
			if !otherPubKey.Equal(pubKey) {
				t.Errorf("otherPubKey.Equal(pubKey) = false, want true")
			}
		})
	}
}

func TestPublicKeyEqualSelf(t *testing.T) {
	for _, tc := range []struct {
		name     string
		instance mldsa.Instance
		keyHex   string
	}{
		{
			name:     "ML-DSA-65",
			instance: mldsa.MLDSA65,
			keyHex:   pubKey65Hex,
		},
		{
			name:     "ML-DSA-87",
			instance: mldsa.MLDSA87,
			keyHex:   pubKey87Hex,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			keyBytes, err := hex.DecodeString(tc.keyHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(pubKeyHex) err = %v, want nil", err)
			}
			pubKey, err := mldsa.NewPublicKey(keyBytes, 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", keyBytes, 123, params, err)
			}
			if !pubKey.Equal(pubKey) {
				t.Errorf("pubKey.Equal(pubKey) = false, want true")
			}
		})
	}
}

type stubKey struct{}

var _ key.Key = (*stubKey)(nil)

func (k *stubKey) Parameters() key.Parameters    { return nil }
func (k *stubKey) Equal(other key.Key) bool      { return true }
func (k *stubKey) IDRequirement() (uint32, bool) { return 123, true }

func TestPublicKeyEqual_FalseIfDifferentType(t *testing.T) {
	for _, tc := range []struct {
		name     string
		instance mldsa.Instance
		keyHex   string
	}{
		{
			name:     "ML-DSA-65",
			instance: mldsa.MLDSA65,
			keyHex:   pubKey65Hex,
		},
		{
			name:     "ML-DSA-87",
			instance: mldsa.MLDSA87,
			keyHex:   pubKey87Hex,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			keyBytes, err := hex.DecodeString(tc.keyHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(tc.keyHex) err = %v, want nil", err)
			}
			pubKey, err := mldsa.NewPublicKey(keyBytes, 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", keyBytes, 123, params, err)
			}
			if pubKey.Equal(&stubKey{}) {
				t.Errorf("pubKey.Equal(&stubKey{}) = true, want false")
			}
		})
	}
}

type TestPublicKeyParams struct {
	keyHex         string
	changeKeyBytes bool
	idRequirement  uint32
	instance       mldsa.Instance
	variant        mldsa.Variant
}

func TestPublicKeyEqualFalse(t *testing.T) {
	for _, tc := range []struct {
		name      string
		firstKey  *TestPublicKeyParams
		secondKey *TestPublicKeyParams
	}{
		{
			name: "different ID requirement",
			firstKey: &TestPublicKeyParams{
				keyHex:        pubKey65Hex,
				idRequirement: 123,
				instance:      mldsa.MLDSA65,
				variant:       mldsa.VariantTink,
			},
			secondKey: &TestPublicKeyParams{
				keyHex:        pubKey65Hex,
				idRequirement: 456,
				instance:      mldsa.MLDSA65,
				variant:       mldsa.VariantTink,
			},
		},
		{
			name: "different key bytes",
			firstKey: &TestPublicKeyParams{
				keyHex:        pubKey65Hex,
				idRequirement: 123,
				instance:      mldsa.MLDSA65,
				variant:       mldsa.VariantTink,
			},
			secondKey: &TestPublicKeyParams{
				keyHex:         pubKey65Hex,
				changeKeyBytes: true,
				idRequirement:  123,
				instance:       mldsa.MLDSA65,
				variant:        mldsa.VariantTink,
			},
		},
		{
			name: "different variant",
			firstKey: &TestPublicKeyParams{
				keyHex:        pubKey65Hex,
				idRequirement: 0,
				instance:      mldsa.MLDSA65,
				variant:       mldsa.VariantTink,
			},
			secondKey: &TestPublicKeyParams{
				keyHex:        pubKey65Hex,
				idRequirement: 0,
				instance:      mldsa.MLDSA65,
				variant:       mldsa.VariantNoPrefix,
			},
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			firstKeyBytes, err := hex.DecodeString(tc.firstKey.keyHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(tc.firstKey.keyHex) err = %v, want nil", err)
			}
			if tc.firstKey.changeKeyBytes {
				firstKeyBytes[0] = 0x99
			}
			secondKeyBytes, err := hex.DecodeString(tc.secondKey.keyHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(tc.secondKey.keyHex) err = %v, want nil", err)
			}
			if tc.secondKey.changeKeyBytes {
				secondKeyBytes[0] = 0x99
			}
			firstParams, err := mldsa.NewParameters(tc.firstKey.instance, tc.firstKey.variant)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", tc.firstKey.variant, err)
			}
			firstPubKey, err := mldsa.NewPublicKey(firstKeyBytes, tc.firstKey.idRequirement, firstParams)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", firstKeyBytes, tc.firstKey.idRequirement, firstParams, err)
			}
			secondParams, err := mldsa.NewParameters(tc.secondKey.instance, tc.secondKey.variant)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", tc.secondKey.variant, err)
			}
			secondPubKey, err := mldsa.NewPublicKey(secondKeyBytes, tc.secondKey.idRequirement, secondParams)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", secondKeyBytes, tc.secondKey.idRequirement, secondParams, err)
			}
			if firstPubKey.Equal(secondPubKey) {
				t.Errorf("firstPubKey.Equal(secondPubKey) = true, want false")
			}
		})
	}
}

func TestPublicKeyKeyBytes(t *testing.T) {
	for _, tc := range []struct {
		name     string
		instance mldsa.Instance
		keyHex   string
	}{
		{
			name:     "MLDSA65",
			instance: mldsa.MLDSA65,
			keyHex:   pubKey65Hex,
		},
		{
			name:     "MLDSA87",
			instance: mldsa.MLDSA87,
			keyHex:   pubKey87Hex,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			keyBytes, err := hex.DecodeString(tc.keyHex)
			if err != nil {
				t.Fatalf("hex.DecodeString(tc.keyHex) err = %v, want nil", err)
			}
			pubKey, err := mldsa.NewPublicKey(keyBytes, 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", keyBytes, 123, params, err)
			}
			gotPubKeyBytes := pubKey.KeyBytes()
			if !bytes.Equal(gotPubKeyBytes, keyBytes) {
				t.Errorf("bytes.Equal(gotPubKeyBytes, keyBytes) = false, want true")
			}
			// Make sure a copy is made when creating the public key.
			keyBytes[0] = 0x99
			if bytes.Equal(pubKey.KeyBytes(), keyBytes) {
				t.Errorf("bytes.Equal(pubKey.KeyBytes(), keyBytes) = true, want false")
			}
			// Make sure no changes are made to the internal state of the public key.
			gotPubKeyBytes[1] = 0x99
			if bytes.Equal(pubKey.KeyBytes(), gotPubKeyBytes) {
				t.Errorf("bytes.Equal((pubKey.KeyBytes(), gotPubKeyBytes) = true, want false")
			}
		})
	}
}

var testCases = []struct {
	name             string
	instance         mldsa.Instance
	variant          mldsa.Variant
	privKeyBytesHex  string
	pubKeyBytesHex   string
	idRequirement    uint32
	wantOutputPrefix []byte
}{
	{
		name:             "tink ML-DSA-65",
		instance:         mldsa.MLDSA65,
		variant:          mldsa.VariantTink,
		privKeyBytesHex:  privKey65Hex,
		pubKeyBytesHex:   pubKey65Hex,
		idRequirement:    uint32(0x01020304),
		wantOutputPrefix: []byte{cryptofmt.TinkStartByte, 0x01, 0x02, 0x03, 0x04},
	},
	{
		name:             "tink ML-DSA-87",
		instance:         mldsa.MLDSA87,
		variant:          mldsa.VariantTink,
		privKeyBytesHex:  privKey87Hex,
		pubKeyBytesHex:   pubKey87Hex,
		idRequirement:    uint32(0x01020304),
		wantOutputPrefix: []byte{cryptofmt.TinkStartByte, 0x01, 0x02, 0x03, 0x04},
	},
	{
		name:             "no prefix ML-DSA-65",
		instance:         mldsa.MLDSA65,
		variant:          mldsa.VariantNoPrefix,
		privKeyBytesHex:  privKey65Hex,
		pubKeyBytesHex:   pubKey65Hex,
		idRequirement:    0,
		wantOutputPrefix: nil,
	},
	{
		name:             "no prefix ML-DSA-87",
		instance:         mldsa.MLDSA87,
		variant:          mldsa.VariantNoPrefix,
		privKeyBytesHex:  privKey87Hex,
		pubKeyBytesHex:   pubKey87Hex,
		idRequirement:    0,
		wantOutputPrefix: nil,
	},
}

func TestPrivateKeyNewPrivateKeyWithPublicKey(t *testing.T) {
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, tc.variant)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", tc.variant, err)
			}
			pubKeyBytes, privKeyBytes := getTestKeyPair(t, tc.instance)
			pubKey, err := mldsa.NewPublicKey(pubKeyBytes, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", pubKeyBytes, tc.idRequirement, params, err)
			}
			secretSeed := secretdata.NewBytesFromData(privKeyBytes, insecuresecretdataaccess.Token{})
			privKey, err := mldsa.NewPrivateKeyWithPublicKey(secretSeed, pubKey)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKeyWithPublicKey(%v, %v) err = %v, want nil", secretSeed, pubKey, err)
			}

			// Test IDRequirement.
			gotIDRequrement, gotRequired := privKey.IDRequirement()
			if got, want := gotRequired, params.HasIDRequirement(); got != want {
				t.Errorf("params.HasIDRequirement() = %v, want %v", got, want)
			}
			if got, want := gotIDRequrement, tc.idRequirement; got != want {
				t.Errorf("params.IDRequirement() = %v, want %v", got, want)
			}

			// Test OutputPrefix.
			if got := privKey.OutputPrefix(); !bytes.Equal(got, tc.wantOutputPrefix) {
				t.Errorf("params.OutputPrefix() = %v, want %v", got, tc.wantOutputPrefix)
			}

			// Test Equal.
			otherPubKey, err := mldsa.NewPublicKey(pubKeyBytes, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", pubKeyBytes, tc.idRequirement, params, err)
			}
			otherPrivKey, err := mldsa.NewPrivateKeyWithPublicKey(secretSeed, otherPubKey)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKeyWithPublicKey(%v, %v) err = %v, want nil", secretSeed, pubKey, err)
			}
			if !otherPrivKey.Equal(privKey) {
				t.Errorf("otherPrivKey.Equal(privKey) = false, want true")
			}

			// Test PublicKey.
			got, err := privKey.PublicKey()
			if err != nil {
				t.Fatalf("privKey.PublicKey() err = %v, want nil", err)
			}
			if !got.Equal(pubKey) {
				t.Errorf("privKey.PublicKey().Equal(pubKey) = false, want true")
			}

			// Test Parameters.
			if got := privKey.Parameters(); !got.Equal(params) {
				t.Errorf("privKey.Parameters().Equal(&params) = false, want true")
			}
		})
	}
}

func TestPrivateKeyNewPrivateKey(t *testing.T) {
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			params, err := mldsa.NewParameters(tc.instance, tc.variant)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", tc.variant, err)
			}
			pubKeyBytes, privKeyBytes := getTestKeyPair(t, tc.instance)
			secretSeed := secretdata.NewBytesFromData(privKeyBytes, insecuresecretdataaccess.Token{})
			privKey, err := mldsa.NewPrivateKey(secretSeed, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKey(%v, %v, %v) err = %v, want nil", secretSeed, tc.idRequirement, params, err)
			}

			// Test IDRequirement.
			gotIDRequrement, gotRequired := privKey.IDRequirement()
			if got, want := gotRequired, params.HasIDRequirement(); got != want {
				t.Errorf("params.HasIDRequirement() = %v, want %v", got, want)
			}
			if got, want := gotIDRequrement, tc.idRequirement; got != want {
				t.Errorf("params.IDRequirement() = %v, want %v", got, want)
			}

			// Test OutputPrefix.
			if got := privKey.OutputPrefix(); !bytes.Equal(got, tc.wantOutputPrefix) {
				t.Errorf("params.OutputPrefix() = %v, want %v", got, tc.wantOutputPrefix)
			}

			// Test Equal.
			otherPrivKey, err := mldsa.NewPrivateKey(secretSeed, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKey(%v, %v, %v) err = %v, want nil", secretSeed, tc.idRequirement, params, err)
			}
			if !otherPrivKey.Equal(privKey) {
				t.Errorf("otherPrivKey.Equal(privKey) = false, want true")
			}

			// Test PublicKey.
			want, err := mldsa.NewPublicKey(pubKeyBytes, tc.idRequirement, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", pubKeyBytes, tc.idRequirement, params, err)
			}
			got, err := privKey.PublicKey()
			if err != nil {
				t.Fatalf("privKey.PublicKey() err = %v, want nil", err)
			}
			if !got.Equal(want) {
				t.Errorf("privKey.PublicKey().Equal(want) = false, want true")
			}

			// Test Parameters.
			if got := privKey.Parameters(); !got.Equal(params) {
				t.Errorf("privKey.Parameters().Equal(&params) = false, want true")
			}
		})
	}
}

func TestNewPrivateKeyFails(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			paramsTink, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			paramsNoPrefix, err := mldsa.NewParameters(inst, mldsa.VariantNoPrefix)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantNoPrefix, err)
			}
			for _, tc := range []struct {
				name         string
				params       *mldsa.Parameters
				idRequrement uint32
				privKeyBytes secretdata.Bytes
			}{
				{
					name:         "nil private key bytes",
					params:       paramsTink,
					idRequrement: 123,
					privKeyBytes: secretdata.NewBytesFromData(nil, insecuresecretdataaccess.Token{}),
				},
				{
					name:         "invalid private key bytes size",
					params:       paramsTink,
					idRequrement: 123,
					privKeyBytes: secretdata.NewBytesFromData([]byte("123"), insecuresecretdataaccess.Token{}),
				},
				{
					name:         "empty params",
					params:       &mldsa.Parameters{},
					idRequrement: 123,
					privKeyBytes: secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
				},
				{
					name:         "invalid ID requiremet",
					idRequrement: 123,
					params:       paramsNoPrefix,
					privKeyBytes: secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
				},
			} {
				t.Run(tc.name, func(t *testing.T) {
					if _, err := mldsa.NewPrivateKey(tc.privKeyBytes, tc.idRequrement, tc.params); err == nil {
						t.Errorf("mldsa.NewPrivateKey(%v, %v, %v) err = nil, want error", tc.privKeyBytes, tc.idRequrement, tc.params)
					}
				})
			}
		})
	}
}

func TestNewPrivateKeyWithPublicKeyFails(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			params, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			pubKeyBytes, privKeyBytes := getTestKeyPair(t, inst)
			pubKey, err := mldsa.NewPublicKey(pubKeyBytes, 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", pubKeyBytes, 123, params, err)
			}
			for _, tc := range []struct {
				name            string
				instance        mldsa.Instance
				pubKey          *mldsa.PublicKey
				privateKeyBytes secretdata.Bytes
			}{
				{
					name:            "nil private key bytes",
					pubKey:          pubKey,
					privateKeyBytes: secretdata.NewBytesFromData(nil, insecuresecretdataaccess.Token{}),
				},
				{
					name:            "invalid private key bytes size",
					pubKey:          pubKey,
					privateKeyBytes: secretdata.NewBytesFromData([]byte("123"), insecuresecretdataaccess.Token{}),
				},
				{
					name:            "empty public key",
					pubKey:          &mldsa.PublicKey{},
					privateKeyBytes: secretdata.NewBytesFromData(privKeyBytes, insecuresecretdataaccess.Token{}),
				},
				{
					name:            "nil public key",
					pubKey:          nil,
					privateKeyBytes: secretdata.NewBytesFromData(privKeyBytes, insecuresecretdataaccess.Token{}),
				},
				{
					name:            "invalid public key",
					pubKey:          pubKey,
					privateKeyBytes: secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
				},
			} {
				t.Run(tc.name, func(t *testing.T) {
					if _, err := mldsa.NewPrivateKeyWithPublicKey(tc.privateKeyBytes, tc.pubKey); err == nil {
						t.Errorf("mldsa.NewPrivateKeyWithPublicKey(%v, %v) err = nil, want error", tc.privateKeyBytes, tc.pubKey)
					}
				})
			}
		})
	}
}

func TestPrivateKeyEqualSelf(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			params, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			pubKeyBytes, privKeyBytes := getTestKeyPair(t, inst)
			pubKey, err := mldsa.NewPublicKey(pubKeyBytes, 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v", pubKeyBytes, 123, params, err)
			}
			secretSeed := secretdata.NewBytesFromData(privKeyBytes, insecuresecretdataaccess.Token{})
			privKey, err := mldsa.NewPrivateKeyWithPublicKey(secretSeed, pubKey)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKeyWithPublicKey(%v, %v) err = %v", secretSeed, pubKey, err)
			}
			if !privKey.Equal(privKey) {
				t.Errorf("privKey.Equal(privKey) = false, want true")
			}
		})
	}
}

func TestPrivateKeyEqual_FalseIfDifferentType(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			params, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			pubKeyBytes, privKeyBytes := getTestKeyPair(t, inst)
			pubKey, err := mldsa.NewPublicKey(pubKeyBytes, 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v", pubKeyBytes, 123, params, err)
			}
			secretSeed := secretdata.NewBytesFromData(privKeyBytes, insecuresecretdataaccess.Token{})
			privKey, err := mldsa.NewPrivateKeyWithPublicKey(secretSeed, pubKey)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKeyWithPublicKey(%v, %v) err = %v", secretSeed, pubKey, err)
			}
			if privKey.Equal(&stubKey{}) {
				t.Errorf("privKey.Equal(&stubKey{}) = true, want false")
			}
		})
	}
}

func TestPrivateKeyEqualFalse(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			paramsTink, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			paramsNoPrefix, err := mldsa.NewParameters(inst, mldsa.VariantNoPrefix)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantNoPrefix, err)
			}
			for _, tc := range []struct {
				name           string
				privKeyBytes1  secretdata.Bytes
				params1        *mldsa.Parameters
				idRequirement1 uint32
				privKeyBytes2  secretdata.Bytes
				params2        *mldsa.Parameters
				idRequirement2 uint32
			}{
				{
					name:           "different private key bytes",
					privKeyBytes1:  secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
					params1:        paramsTink,
					idRequirement1: 123,
					privKeyBytes2:  secretdata.NewBytesFromData([]byte("12345678123456781234567812345679"), insecuresecretdataaccess.Token{}),
					params2:        paramsTink,
					idRequirement2: 123,
				},
				{
					name:           "different ID requirement",
					privKeyBytes1:  secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
					params1:        paramsTink,
					idRequirement1: 123,
					privKeyBytes2:  secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
					params2:        paramsTink,
					idRequirement2: 456,
				},
				{
					name:           "different params",
					privKeyBytes1:  secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
					params1:        paramsTink,
					idRequirement1: 0,
					privKeyBytes2:  secretdata.NewBytesFromData([]byte("12345678123456781234567812345678"), insecuresecretdataaccess.Token{}),
					params2:        paramsNoPrefix,
					idRequirement2: 0,
				},
			} {
				t.Run(tc.name, func(t *testing.T) {
					firstPrivKey, err := mldsa.NewPrivateKey(tc.privKeyBytes1, tc.idRequirement1, tc.params1)
					if err != nil {
						t.Fatalf("mldsa.NewPrivateKey(%v, %v, %v) err = %v", tc.privKeyBytes1, tc.idRequirement1, tc.params1, err)
					}
					secondPrivKey, err := mldsa.NewPrivateKey(tc.privKeyBytes2, tc.idRequirement2, tc.params2)
					if err != nil {
						t.Fatalf("mldsa.NewPrivateKey(%v, %v, %v) err = %v", tc.privKeyBytes2, tc.idRequirement2, tc.params2, err)
					}
					if firstPrivKey.Equal(secondPrivKey) {
						t.Errorf("firstPrivKey.Equal(secondPrivKey) = true, want false")
					}
				})
			}
		})
	}
}

func TestPrivateKeyKeyBytes(t *testing.T) {
	for _, inst := range []mldsa.Instance{
		mldsa.MLDSA65,
		mldsa.MLDSA87,
	} {
		t.Run(fmt.Sprintf("%s", inst), func(t *testing.T) {
			pubKeyBytes, privKeyBytes := getTestKeyPair(t, inst)
			params, err := mldsa.NewParameters(inst, mldsa.VariantTink)
			if err != nil {
				t.Fatalf("mldsa.NewParameters(%v) err = %v, want nil", mldsa.VariantTink, err)
			}
			pubKey, err := mldsa.NewPublicKey([]byte(pubKeyBytes), 123, params)
			if err != nil {
				t.Fatalf("mldsa.NewPublicKey(%v, %v, %v) err = %v, want nil", []byte(pubKeyBytes), 123, params, err)
			}
			secretSeed := secretdata.NewBytesFromData([]byte(privKeyBytes), insecuresecretdataaccess.Token{})
			privKey, err := mldsa.NewPrivateKeyWithPublicKey(secretSeed, pubKey)
			if err != nil {
				t.Fatalf("mldsa.NewPrivateKeyWithPublicKey(%v, %v) err = %v, want nil", secretSeed, pubKey, err)
			}
			if got, want := privKey.PrivateKeyBytes().Data(insecuresecretdataaccess.Token{}), []byte(privKeyBytes); !bytes.Equal(got, want) {
				t.Errorf("bytes.Equal(got, want) = false, want true")
			}
		})
	}
}

func getTestKeyPair(t *testing.T, instance mldsa.Instance) ([]byte, []byte) {
	t.Helper()
	switch instance {
	case mldsa.MLDSA65:
		pubKeyBytes, err := hex.DecodeString(pubKey65Hex)
		if err != nil {
			t.Fatalf("hex.DecodeString(pubKeyHex) err = %v, want nil", err)
		}
		privKeyBytes, err := hex.DecodeString(privKey65Hex)
		if err != nil {
			t.Fatalf("hex.DecodeString(privKeyHex) err = %v, want nil", err)
		}
		return pubKeyBytes, privKeyBytes
	case mldsa.MLDSA87:
		pubKeyBytes, err := hex.DecodeString(pubKey87Hex)
		if err != nil {
			t.Fatalf("hex.DecodeString(pubKeyHex) err = %v, want nil", err)
		}
		privKeyBytes, err := hex.DecodeString(privKey87Hex)
		if err != nil {
			t.Fatalf("hex.DecodeString(privKeyHex) err = %v, want nil", err)
		}
		return pubKeyBytes, privKeyBytes
	default:
		t.Fatalf("unsupported instance: %v", instance)
	}
	return nil, nil
}

func TestKeyCreator(t *testing.T) {
	params, err := mldsa.NewParameters(mldsa.MLDSA65, mldsa.VariantTink)
	if err != nil {
		t.Fatalf("mldsa.NewParameters() err = %v, want nil", err)
	}

	key, err := keygenregistry.CreateKey(params, 0x1234)
	if err != nil {
		t.Fatalf("keygenregistry.CreateKey(%v, 0x1234) err = %v, want nil", params, err)
	}
	mldsaPrivateKey, ok := key.(*mldsa.PrivateKey)
	if !ok {
		t.Fatalf("keygenregistry.CreateKey(%v, 0x1234) returned key of type %T, want %T", params, key, (*mldsa.PrivateKey)(nil))
	}
	idRequirement, hasIDRequirement := mldsaPrivateKey.IDRequirement()
	if !hasIDRequirement || idRequirement != 0x1234 {
		t.Errorf("mldsaPrivateKey.IDRequirement() (%v, %v), want (%v, %v)", idRequirement, hasIDRequirement, 123, true)
	}
	if diff := cmp.Diff(mldsaPrivateKey.Parameters(), params); diff != "" {
		t.Errorf("mldsaPrivateKey.Parameters() diff (-want +got):\n%s", diff)
	}
}

func TestPrivateKeyCreator_Fails(t *testing.T) {
	paramsNoPrefix, err := mldsa.NewParameters(mldsa.MLDSA65, mldsa.VariantNoPrefix)
	if err != nil {
		t.Fatalf("mldsa.NewParameters() err = %v, want nil", err)
	}
	for _, tc := range []struct {
		name          string
		params        *mldsa.Parameters
		idRequirement uint32
	}{
		{
			name:          "invalid id requirement",
			params:        paramsNoPrefix,
			idRequirement: 0x1234,
		},
		{
			name:          "invalid parameters",
			params:        &mldsa.Parameters{},
			idRequirement: 0x1234,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			if _, err := keygenregistry.CreateKey(tc.params, tc.idRequirement); err == nil {
				t.Errorf("keygenregistry.CreateKey(%v, %v) err = nil, want error", tc.params, tc.idRequirement)
			}
		})
	}
}
