// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build !fips140v1.0

package mldsa_test

import (
	"bytes"
	"crypto"
	"crypto/fips140"
	"crypto/internal/cryptotest"
	. "crypto/mldsa"
	"crypto/sha3"
	"encoding/hex"
	"flag"
	"math/rand/v2"
	"strings"
	"testing"
)

var _ crypto.Signer = (*PrivateKey)(nil)

var sixtyMillionFlag = flag.Bool("60million", false, "run 60M-iterations accumulated test")

// TestAccumulated accumulates 10k (or 100, or 60M) random vectors and checks
// the hash of the result, to avoid checking in megabytes of test vectors.
//
// 60M in particular is enough to give a 99.9% chance of hitting every value in
// the base field.
//
//	1-((q-1)/q)^60000000 ~= 0.9992
//
// If setting -60million, remember to also set -timeout 0.
func TestAccumulated(t *testing.T) {
	t.Run("ML-DSA-44/100", func(t *testing.T) {
		testAccumulated(t, MLDSA44(), 100,
			"d51148e1f9f4fa1a723a6cf42e25f2a99eb5c1b378b3d2dbbd561b1203beeae4")
	})
	t.Run("ML-DSA-65/100", func(t *testing.T) {
		testAccumulated(t, MLDSA65(), 100,
			"8358a1843220194417cadbc2651295cd8fc65125b5a5c1a239a16dc8b57ca199")
	})
	t.Run("ML-DSA-87/100", func(t *testing.T) {
		testAccumulated(t, MLDSA87(), 100,
			"8c3ad714777622b8f21ce31bb35f71394f23bc0fcf3c78ace5d608990f3b061b")
	})
	if !testing.Short() {
		t.Run("ML-DSA-44/10k", func(t *testing.T) {
			t.Parallel()
			testAccumulated(t, MLDSA44(), 10000,
				"e7fd21f6a59bcba60d65adc44404bb29a7c00e5d8d3ec06a732c00a306a7d143")
		})
		t.Run("ML-DSA-65/10k", func(t *testing.T) {
			t.Parallel()
			testAccumulated(t, MLDSA65(), 10000,
				"5ff5e196f0b830c3b10a9eb5358e7c98a3a20136cb677f3ae3b90175c3ace329")
		})
		t.Run("ML-DSA-87/10k", func(t *testing.T) {
			t.Parallel()
			testAccumulated(t, MLDSA87(), 10000,
				"80a8cf39317f7d0be0e24972c51ac152bd2a3e09bc0c32ce29dd82c4e7385e60")
		})
	}
	if *sixtyMillionFlag {
		t.Run("ML-DSA-44/60M", func(t *testing.T) {
			t.Parallel()
			testAccumulated(t, MLDSA44(), 60000000,
				"080b48049257f5cd30dee17d6aa393d6c42fe52a29099df84a460ebaf4b02330")
		})
		t.Run("ML-DSA-65/60M", func(t *testing.T) {
			t.Parallel()
			testAccumulated(t, MLDSA65(), 60000000,
				"0af0165db2b180f7a83dbecad1ccb758b9c2d834b7f801fc49dd572a9d4b1e83")
		})
		t.Run("ML-DSA-87/60M", func(t *testing.T) {
			t.Parallel()
			testAccumulated(t, MLDSA87(), 60000000,
				"011166e9d5032c9bdc5c9bbb5dbb6c86df1c3d9bf3570b65ebae942dd9830057")
		})
	}
}

func testAccumulated(t *testing.T, params Parameters, n int, expected string) {
	s := sha3.NewSHAKE128()
	o := sha3.NewSHAKE128()
	seed := make([]byte, PrivateKeySize)
	msg := make([]byte, 0)

	for i := 0; i < n; i++ {
		s.Read(seed)
		dk, err := NewPrivateKey(params, seed)
		if err != nil {
			t.Fatalf("NewPrivateKey: %v", err)
		}
		pk := dk.PublicKey().Bytes()
		o.Write(pk)
		sig, err := dk.SignDeterministic(msg, nil)
		if err != nil {
			t.Fatalf("SignDeterministic: %v", err)
		}
		o.Write(sig)
		pub, err := NewPublicKey(params, pk)
		if err != nil {
			t.Fatalf("NewPublicKey: %v", err)
		}
		if *pub != *dk.PublicKey() {
			t.Fatalf("public key mismatch")
		}
		if err := Verify(dk.PublicKey(), msg, sig, nil); err != nil {
			t.Fatalf("Verify: %v", err)
		}
	}

	sum := make([]byte, 32)
	o.Read(sum)
	got := hex.EncodeToString(sum)
	if got != expected {
		t.Errorf("got %s, expected %s", got, expected)
	}
}

func testAllParameters(t *testing.T, f func(*testing.T, Parameters)) {
	for _, params := range []Parameters{MLDSA44(), MLDSA65(), MLDSA87()} {
		t.Run(params.String(), func(t *testing.T) {
			f(t, params)
		})
	}
}

func TestGenerateKey(t *testing.T) {
	testAllParameters(t, testGenerateKey)
}

func testGenerateKey(t *testing.T, params Parameters) {
	k1, err := GenerateKey(params)
	if err != nil {
		t.Fatalf("GenerateKey: %v", err)
	}
	k2, err := GenerateKey(params)
	if err != nil {
		t.Fatalf("GenerateKey: %v", err)
	}
	if k1.Equal(k2) {
		t.Errorf("two generated keys are equal")
	}
	k1x, err := NewPrivateKey(params, k1.Bytes())
	if err != nil {
		t.Fatalf("NewPrivateKey: %v", err)
	}
	if !k1.Equal(k1x) {
		t.Errorf("generated key and re-parsed key are not equal")
	}
}

func TestAllocations(t *testing.T) {
	// We allocate
	//
	//   - the PrivateKey (k and kk) structs
	//   - their temporary inner structs (2x)
	//   - the public key (pkBytes) and signature (sig) byte slices
	//   - the Options argument to Sign
	//
	// on the heap. The structs are too large for the stack, the byte slices are
	// variable-sized, and Options is cast into an interface.
	//
	// Still, check we are not slipping more allocations in.
	var expected float64 = 7
	if fips140.Enabled() {
		// The PCT does a sign/verify cycle, which allocates a signature slice.
		expected += 1
	}
	if fips140.Version() == "v1.26.0" {
		// The v1.26.0 implementation precomputes PublicKey, making it large
		// enough to require heap allocation. Add pk, its inner struct, and the
		// return value of k.PublicKey().
		expected += 3
	}
	cryptotest.SkipTestAllocations(t)
	if allocs := testing.AllocsPerRun(100, func() {
		k, err := GenerateKey(MLDSA44())
		if err != nil {
			t.Fatalf("GenerateKey: %v", err)
		}
		seed := k.Bytes()
		kk, err := NewPrivateKey(MLDSA44(), seed)
		if err != nil {
			t.Fatalf("NewPrivateKey: %v", err)
		}
		if !k.Equal(kk) {
			t.Fatalf("keys not equal")
		}
		pkBytes := k.PublicKey().Bytes()
		pk, err := NewPublicKey(MLDSA44(), pkBytes)
		if err != nil {
			t.Fatalf("NewPublicKey: %v", err)
		}
		message := []byte("Hello, world!")
		context := "test"
		sig, err := k.Sign(nil, message, &Options{Context: context})
		if err != nil {
			t.Fatalf("Sign: %v", err)
		}
		if err := Verify(pk, message, sig, &Options{Context: context}); err != nil {
			t.Fatalf("Verify: %v", err)
		}
	}); allocs > expected {
		t.Errorf("expected %0.0f allocations, got %0.1f", expected, allocs)
	}
}

func TestParametersIdentity(t *testing.T) {
	// Per the MLDSA*() docs, repeated calls return the same value, suitable for
	// equality checks and switch statements.
	if MLDSA44() != MLDSA44() || MLDSA65() != MLDSA65() || MLDSA87() != MLDSA87() {
		t.Errorf("MLDSA*() returned different values across calls")
	}
	if MLDSA44() == MLDSA65() || MLDSA65() == MLDSA87() || MLDSA44() == MLDSA87() {
		t.Errorf("distinct parameter sets compare equal")
	}
}

// computeMu reproduces μ = SHAKE256(SHAKE256(pk, 64) || 0x00 || ctxlen || ctx ||
// msg, 64) per FIPS 204, used to drive the External μ signing path.
func computeMu(pk, ctx, msg []byte) []byte {
	tr := sha3.NewSHAKE256()
	tr.Write(pk)
	trOut := make([]byte, 64)
	tr.Read(trOut)

	h := sha3.NewSHAKE256()
	h.Write(trOut)
	h.Write([]byte{0x00, byte(len(ctx))})
	h.Write(ctx)
	h.Write(msg)
	out := make([]byte, 64)
	h.Read(out)
	return out
}

// fakeSignerOpts is a [crypto.SignerOpts] whose [HashFunc] returns h, used to
// exercise the opts-dispatch paths in [PrivateKey.Sign] without going through
// [Options].
type fakeSignerOpts struct{ h crypto.Hash }

func (f fakeSignerOpts) HashFunc() crypto.Hash { return f.h }

func TestSign(t *testing.T) {
	testAllParameters(t, func(t *testing.T, params Parameters) {
		sk, err := GenerateKey(params)
		if err != nil {
			t.Fatalf("GenerateKey: %v", err)
		}
		pk := sk.PublicKey()
		msg := []byte("test message")

		// nil opts and &Options{} must be equivalent (and both interoperable
		// with a nil/zero Verify opts).
		sig1, err := sk.Sign(nil, msg, nil)
		if err != nil {
			t.Fatalf("Sign(nil opts): %v", err)
		}
		if got := len(sig1); got != params.SignatureSize() {
			t.Errorf("len(sig) = %d, want %d", got, params.SignatureSize())
		}
		if err := Verify(pk, msg, sig1, nil); err != nil {
			t.Errorf("Verify of nil-opts signature with nil opts: %v", err)
		}
		if err := Verify(pk, msg, sig1, &Options{}); err != nil {
			t.Errorf("Verify of nil-opts signature with empty Options: %v", err)
		}

		sig2, err := sk.Sign(nil, msg, &Options{})
		if err != nil {
			t.Fatalf("Sign(&Options{}): %v", err)
		}
		if err := Verify(pk, msg, sig2, nil); err != nil {
			t.Errorf("Verify of empty-Options signature with nil opts: %v", err)
		}

		// A non-*Options crypto.SignerOpts whose HashFunc returns 0 must
		// also sign directly, with empty context.
		sig3, err := sk.Sign(nil, msg, fakeSignerOpts{h: 0})
		if err != nil {
			t.Fatalf("Sign(fakeSignerOpts{0}): %v", err)
		}
		if err := Verify(pk, msg, sig3, nil); err != nil {
			t.Errorf("Verify of fake-opts signature: %v", err)
		}

		// crypto.Hash(0) similarly: HashFunc returns 0.
		sig4, err := sk.Sign(nil, msg, crypto.Hash(0))
		if err != nil {
			t.Fatalf("Sign(crypto.Hash(0)): %v", err)
		}
		if err := Verify(pk, msg, sig4, nil); err != nil {
			t.Errorf("Verify of Hash(0)-opts signature: %v", err)
		}

		// A wrong HashFunc must produce errInvalidSignerOpts.
		if _, err := sk.Sign(nil, msg, crypto.SHA256); err == nil {
			t.Errorf("Sign with crypto.SHA256 opts: want error, got nil")
		}
		if _, err := sk.SignDeterministic(msg, crypto.SHA256); err == nil {
			t.Errorf("SignDeterministic with crypto.SHA256 opts: want error, got nil")
		}

		// SignDeterministic with nil and &Options{} must agree byte-for-byte.
		detA, err := sk.SignDeterministic(msg, nil)
		if err != nil {
			t.Fatalf("SignDeterministic(nil): %v", err)
		}
		detB, err := sk.SignDeterministic(msg, &Options{})
		if err != nil {
			t.Fatalf("SignDeterministic(&Options{}): %v", err)
		}
		if !bytes.Equal(detA, detB) {
			t.Errorf("SignDeterministic with nil and &Options{} differ")
		}

		// A different Context produces a different deterministic signature
		// and verification with a mismatched context must fail.
		detCtx, err := sk.SignDeterministic(msg, &Options{Context: "ctx"})
		if err != nil {
			t.Fatalf("SignDeterministic(ctx): %v", err)
		}
		if string(detCtx) == string(detA) {
			t.Errorf("SignDeterministic with empty and non-empty context match")
		}
		if err := Verify(pk, msg, detCtx, nil); err == nil {
			t.Errorf("Verify of context signature with empty context: want error, got nil")
		}
		if err := Verify(pk, msg, detCtx, &Options{Context: "ctx"}); err != nil {
			t.Errorf("Verify with matching context: %v", err)
		}

		// Context >255 bytes is rejected by the underlying implementation.
		longCtx := strings.Repeat("x", 256)
		if _, err := sk.Sign(nil, msg, &Options{Context: longCtx}); err == nil {
			t.Errorf("Sign with 256-byte context: want error, got nil")
		}
		if _, err := sk.SignDeterministic(msg, &Options{Context: longCtx}); err == nil {
			t.Errorf("SignDeterministic with 256-byte context: want error, got nil")
		}
		if err := Verify(pk, msg, detA, &Options{Context: longCtx}); err == nil {
			t.Errorf("Verify with 256-byte context: want error, got nil")
		}

		// Tampered signature must not verify.
		sigTampered := bytes.Clone(sig1)
		sigTampered[len(sigTampered)/2] ^= 0x01
		if err := Verify(pk, msg, sigTampered, nil); err == nil {
			t.Errorf("Verify of tampered signature: want error, got nil")
		}

		// Modified message must not verify against the original signature.
		msgTampered := bytes.Clone(msg)
		msgTampered[0] ^= 0x01
		if err := Verify(pk, msgTampered, sig1, nil); err == nil {
			t.Errorf("Verify of modified message: want error, got nil")
		}

		// Signature from a different key must not verify.
		skOther, err := GenerateKey(params)
		if err != nil {
			t.Fatalf("GenerateKey: %v", err)
		}
		sigOther, err := skOther.SignDeterministic(msg, nil)
		if err != nil {
			t.Fatalf("SignDeterministic: %v", err)
		}
		if err := Verify(pk, msg, sigOther, nil); err == nil {
			t.Errorf("Verify of signature from a different key: want error, got nil")
		}
	})
}

func TestExternalMu(t *testing.T) {
	testAllParameters(t, func(t *testing.T, params Parameters) {
		sk, err := GenerateKey(params)
		if err != nil {
			t.Fatalf("GenerateKey: %v", err)
		}
		pk := sk.PublicKey()
		pkBytes := pk.Bytes()
		msg := []byte("hello mu")

		for _, ctx := range []string{"", "ctx"} {
			μ := computeMu(pkBytes, []byte(ctx), msg)
			sig, err := sk.Sign(nil, μ, crypto.MLDSAMu)
			if err != nil {
				t.Fatalf("Sign(MLDSAMu, ctx=%q): %v", ctx, err)
			}
			if err := Verify(pk, msg, sig, &Options{Context: ctx}); err != nil {
				t.Errorf("Verify of MLDSAMu signature, ctx=%q: %v", ctx, err)
			}

			detSig, err := sk.SignDeterministic(μ, crypto.MLDSAMu)
			if err != nil {
				t.Fatalf("SignDeterministic(MLDSAMu, ctx=%q): %v", ctx, err)
			}
			if err := Verify(pk, msg, detSig, &Options{Context: ctx}); err != nil {
				t.Errorf("Verify of deterministic MLDSAMu signature, ctx=%q: %v", ctx, err)
			}
			detSig2, err := sk.SignDeterministic(μ, crypto.MLDSAMu)
			if err != nil {
				t.Fatalf("SignDeterministic(MLDSAMu) second call: %v", err)
			}
			if string(detSig) != string(detSig2) {
				t.Errorf("SignDeterministic(MLDSAMu) is not deterministic")
			}
		}

		// Cross-context: μ computed under one ctx must not verify under another.
		μA := computeMu(pkBytes, []byte("a"), msg)
		sigA, err := sk.Sign(nil, μA, crypto.MLDSAMu)
		if err != nil {
			t.Fatalf("Sign(MLDSAMu, ctx=a): %v", err)
		}
		if err := Verify(pk, msg, sigA, &Options{Context: "b"}); err == nil {
			t.Errorf("Verify of MLDSAMu(ctx=a) signature with ctx=b: want error, got nil")
		}

		// Tampered MLDSAMu signature must not verify.
		sigTampered := bytes.Clone(sigA)
		sigTampered[len(sigTampered)/2] ^= 0x01
		if err := Verify(pk, msg, sigTampered, &Options{Context: "a"}); err == nil {
			t.Errorf("Verify of tampered MLDSAMu signature: want error, got nil")
		}

		// Wrong-length μ must be rejected.
		if _, err := sk.Sign(nil, make([]byte, 32), crypto.MLDSAMu); err == nil {
			t.Errorf("Sign(MLDSAMu) with 32-byte input: want error, got nil")
		}
		if _, err := sk.SignDeterministic(make([]byte, 32), crypto.MLDSAMu); err == nil {
			t.Errorf("SignDeterministic(MLDSAMu) with 32-byte input: want error, got nil")
		}
	})
}

func TestPublicKey(t *testing.T) {
	cases := []struct {
		params  Parameters
		name    string
		pkSize  int
		sigSize int
	}{
		{MLDSA44(), "ML-DSA-44", MLDSA44PublicKeySize, MLDSA44SignatureSize},
		{MLDSA65(), "ML-DSA-65", MLDSA65PublicKeySize, MLDSA65SignatureSize},
		{MLDSA87(), "ML-DSA-87", MLDSA87PublicKeySize, MLDSA87SignatureSize},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if got := tc.params.String(); got != tc.name {
				t.Errorf("Parameters.String() = %q, want %q", got, tc.name)
			}
			if got := tc.params.PublicKeySize(); got != tc.pkSize {
				t.Errorf("Parameters.PublicKeySize() = %d, want %d", got, tc.pkSize)
			}
			if got := tc.params.SignatureSize(); got != tc.sigSize {
				t.Errorf("Parameters.SignatureSize() = %d, want %d", got, tc.sigSize)
			}

			sk, err := GenerateKey(tc.params)
			if err != nil {
				t.Fatalf("GenerateKey: %v", err)
			}
			pk := sk.PublicKey()
			if got := pk.Parameters(); got != tc.params {
				t.Errorf("PublicKey.Parameters() = %v, want %v", got, tc.params)
			}
			if got := len(pk.Bytes()); got != tc.params.PublicKeySize() {
				t.Errorf("len(PublicKey.Bytes()) = %d, want %d", got, tc.params.PublicKeySize())
			}
			if got := len(sk.Bytes()); got != PrivateKeySize {
				t.Errorf("len(PrivateKey.Bytes()) = %d, want %d", got, PrivateKeySize)
			}

			// Public() returns the same key as PublicKey().
			anyPub := sk.Public()
			pub2, ok := anyPub.(*PublicKey)
			if !ok {
				t.Fatalf("PrivateKey.Public() = %T, want *PublicKey", anyPub)
			}
			if !pk.Equal(pub2) {
				t.Errorf("PrivateKey.Public() does not equal PublicKey()")
			}

			// Round-trip via NewPrivateKey/NewPublicKey.
			sk2, err := NewPrivateKey(tc.params, sk.Bytes())
			if err != nil {
				t.Fatalf("NewPrivateKey round-trip: %v", err)
			}
			if !sk.Equal(sk2) {
				t.Errorf("PrivateKey round-trip not equal")
			}
			pk2, err := NewPublicKey(tc.params, pk.Bytes())
			if err != nil {
				t.Fatalf("NewPublicKey round-trip: %v", err)
			}
			if !pk.Equal(pk2) {
				t.Errorf("PublicKey round-trip not equal")
			}
		})
	}
}

func TestEqualWrongType(t *testing.T) {
	sk, err := GenerateKey(MLDSA44())
	if err != nil {
		t.Fatalf("GenerateKey: %v", err)
	}
	if sk.Equal("not a key") {
		t.Errorf("PrivateKey.Equal(string) = true, want false")
	}
	if sk.Equal((*PublicKey)(nil)) {
		t.Errorf("PrivateKey.Equal(*PublicKey) = true, want false")
	}
	if sk.PublicKey().Equal("not a key") {
		t.Errorf("PublicKey.Equal(string) = true, want false")
	}
	if sk.PublicKey().Equal((*PrivateKey)(nil)) {
		t.Errorf("PublicKey.Equal(*PrivateKey) = true, want false")
	}

	// Distinct keys are not Equal.
	sk2, err := GenerateKey(MLDSA44())
	if err != nil {
		t.Fatalf("GenerateKey: %v", err)
	}
	if sk.Equal(sk2) {
		t.Errorf("two random PrivateKeys are Equal")
	}
	if sk.PublicKey().Equal(sk2.PublicKey()) {
		t.Errorf("two random PublicKeys are Equal")
	}
}

func TestInvalidParameters(t *testing.T) {
	var zero Parameters
	if _, err := GenerateKey(zero); err == nil {
		t.Errorf("GenerateKey(zero Parameters): want error, got nil")
	}
	if _, err := NewPrivateKey(zero, make([]byte, PrivateKeySize)); err == nil {
		t.Errorf("NewPrivateKey(zero Parameters): want error, got nil")
	}
	if _, err := NewPublicKey(zero, make([]byte, MLDSA44PublicKeySize)); err == nil {
		t.Errorf("NewPublicKey(zero Parameters): want error, got nil")
	}
}

func TestInvalidSize(t *testing.T) {
	testAllParameters(t, func(t *testing.T, params Parameters) {
		if _, err := NewPrivateKey(params, make([]byte, PrivateKeySize-1)); err == nil {
			t.Errorf("NewPrivateKey with short seed: want error, got nil")
		}
		if _, err := NewPrivateKey(params, make([]byte, PrivateKeySize+1)); err == nil {
			t.Errorf("NewPrivateKey with long seed: want error, got nil")
		}
		if _, err := NewPublicKey(params, make([]byte, params.PublicKeySize()-1)); err == nil {
			t.Errorf("NewPublicKey with short encoding: want error, got nil")
		}
		if _, err := NewPublicKey(params, make([]byte, params.PublicKeySize()+1)); err == nil {
			t.Errorf("NewPublicKey with long encoding: want error, got nil")
		}

		sk, err := GenerateKey(params)
		if err != nil {
			t.Fatalf("GenerateKey: %v", err)
		}
		msg := []byte("test message")
		sig, err := sk.SignDeterministic(msg, nil)
		if err != nil {
			t.Fatalf("SignDeterministic: %v", err)
		}
		if err := Verify(sk.PublicKey(), msg, sig[:len(sig)-1], nil); err == nil {
			t.Errorf("Verify with short signature: want error, got nil")
		}
		if err := Verify(sk.PublicKey(), msg, append(sig, 0), nil); err == nil {
			t.Errorf("Verify with long signature: want error, got nil")
		}
	})

	// Cross-parameter mismatch: an MLDSA65 public key encoding is rejected by
	// MLDSA44 (and vice versa), because the lengths differ.
	sk65, err := GenerateKey(MLDSA65())
	if err != nil {
		t.Fatalf("GenerateKey(MLDSA65): %v", err)
	}
	if _, err := NewPublicKey(MLDSA44(), sk65.PublicKey().Bytes()); err == nil {
		t.Errorf("NewPublicKey(MLDSA44, MLDSA65 encoding): want error, got nil")
	}
}

func TestUninitialized(t *testing.T) {
	t.Run("Verify", func(t *testing.T) {
		msg := []byte("attacker-controlled message")
		sig := make([]byte, MLDSA44SignatureSize)

		cases := []struct {
			name string
			fn   func() error
		}{
			{"empty signature/nil opts", func() error {
				var pk PublicKey
				return Verify(&pk, msg, nil, nil)
			}},
			{"empty signature/empty opts", func() error {
				var pk PublicKey
				return Verify(&pk, msg, nil, &Options{})
			}},
			{"zero length signature", func() error {
				var pk PublicKey
				return Verify(&pk, msg, []byte{}, nil)
			}},
			{"full length signature", func() error {
				var pk PublicKey
				return Verify(&pk, msg, sig, nil)
			}},
			{"full length signature/with context", func() error {
				var pk PublicKey
				return Verify(&pk, msg, sig, &Options{Context: "ctx"})
			}},
		}
		for _, c := range cases {
			t.Run(c.name, func(t *testing.T) {
				err, panicked := call(c.fn)
				if panicked != nil {
					t.Errorf("Verify panicked: %v", panicked)
				}
				if err == nil {
					t.Error("Verify accepted uninitialized PublicKey, want error")
				}
			})
		}
	})

	signFuncs := []struct {
		name string
		sign func(sk *PrivateKey, msg []byte, opts crypto.SignerOpts) ([]byte, error)
	}{
		{"Sign", func(sk *PrivateKey, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
			return sk.Sign(nil, msg, opts)
		}},
		{"SignDeterministic", func(sk *PrivateKey, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
			return sk.SignDeterministic(msg, opts)
		}},
	}
	for _, f := range signFuncs {
		t.Run(f.name, func(t *testing.T) {
			msg := []byte("message")

			cases := []struct {
				name string
				fn   func() error
			}{
				{"nil opts", func() error {
					var sk PrivateKey
					_, err := sk.Sign(nil, msg, nil)
					return err
				}},
				{"empty opts", func() error {
					var sk PrivateKey
					_, err := sk.Sign(nil, msg, &Options{})
					return err
				}},
				{"typed nil opts", func() error {
					var sk PrivateKey
					_, err := sk.Sign(nil, msg, (*Options)(nil))
					return err
				}},
				{"mu opts", func() error {
					var sk PrivateKey
					_, err := sk.Sign(nil, msg, muOptions{})
					return err
				}},
			}
			for _, c := range cases {
				t.Run(c.name, func(t *testing.T) {
					err, panicked := call(c.fn)
					if panicked != nil {
						t.Errorf("panicked: %v", panicked)
					}
					if err == nil {
						t.Error("accepted zero-value PrivateKey, want error")
					}
				})
			}
		})
	}

	t.Run("TypedNilOptions", func(t *testing.T) {
		sk, err := GenerateKey(MLDSA44())
		if err != nil {
			t.Fatal(err)
		}
		msg := []byte("message")

		t.Run("SignDeterministic", func(t *testing.T) {
			want, err := sk.SignDeterministic(msg, nil)
			if err != nil {
				t.Fatalf("SignDeterministic(nil opts): %v", err)
			}
			var got []byte
			_, panicked := call(func() (err error) {
				got, err = sk.SignDeterministic(msg, (*Options)(nil))
				return err
			})
			if panicked != nil {
				t.Fatalf("SignDeterministic(typed-nil opts) panicked: %v", panicked)
			}
			if !bytes.Equal(got, want) {
				t.Error("SignDeterministic(typed-nil opts) != SignDeterministic(nil opts)")
			}
		})

		t.Run("Sign", func(t *testing.T) {
			var sig []byte
			_, panicked := call(func() (err error) {
				sig, err = sk.Sign(nil, msg, (*Options)(nil))
				return err
			})
			if panicked != nil {
				t.Fatalf("Sign(typed-nil opts) panicked: %v", panicked)
			}
			if err := Verify(sk.PublicKey(), msg, sig, nil); err != nil {
				t.Errorf("signature made with typed-nil opts does not verify under empty context: %v", err)
			}
		})
	})
}

func call(fn func() error) (err error, panicked any) {
	defer func() { panicked = recover() }()
	err = fn()
	return err, nil
}

type muOptions struct{}

func (muOptions) HashFunc() crypto.Hash { return crypto.MLDSAMu }

func BenchmarkSign(b *testing.B) {
	// Signing works by rejection sampling, which introduces massive variance in
	// individual signing times. To get stable but correct results, we benchmark
	// a series of representative operations, engineered to have the same
	// distribution of rejection counts and reasons as the average case. See also
	// https://words.filippo.io/rsa-keygen-bench/ for a similar approach.
	b.Run("ML-DSA-44", func(b *testing.B) {
		benchmarkSign(b, MLDSA44(), benchmarkMessagesMLDSA44)
	})
	b.Run("ML-DSA-65", func(b *testing.B) {
		benchmarkSign(b, MLDSA65(), benchmarkMessagesMLDSA65)
	})
	b.Run("ML-DSA-87", func(b *testing.B) {
		benchmarkSign(b, MLDSA87(), benchmarkMessagesMLDSA87)
	})
}

func benchmarkSign(b *testing.B, params Parameters, messages []string) {
	seed := make([]byte, 32)
	priv, err := NewPrivateKey(params, seed)
	if err != nil {
		b.Fatalf("NewPrivateKey: %v", err)
	}
	rand.Shuffle(len(messages), func(i, j int) {
		messages[i], messages[j] = messages[j], messages[i]
	})
	i := 0
	for b.Loop() {
		msg := messages[i]
		if i++; i >= len(messages) {
			i = 0
		}
		priv.SignDeterministic([]byte(msg), nil)
	}
}

func BenchmarkVerify(b *testing.B) {
	b.Run("ML-DSA-44", func(b *testing.B) {
		benchmarkVerify(b, MLDSA44())
	})
	b.Run("ML-DSA-65", func(b *testing.B) {
		benchmarkVerify(b, MLDSA65())
	})
	b.Run("ML-DSA-87", func(b *testing.B) {
		benchmarkVerify(b, MLDSA87())
	})
}

func benchmarkVerify(b *testing.B, params Parameters) {
	priv, err := GenerateKey(params)
	if err != nil {
		b.Fatalf("GenerateKey: %v", err)
	}
	msg := make([]byte, 128)
	sig, err := priv.SignDeterministic(msg, &Options{Context: "context"})
	if err != nil {
		b.Fatalf("SignDeterministic: %v", err)
	}
	pub := priv.PublicKey().Bytes()

	// "Whole" runs both public key parsing and signature verification,
	// since pre-computation can be easily moved between the two, but in practice
	// most uses of verification are for fresh public keys (unlike signing).
	b.Run("Whole", func(b *testing.B) {
		for b.Loop() {
			pk, err := NewPublicKey(params, pub)
			if err != nil {
				b.Fatalf("NewPublicKey: %v", err)
			}
			if err := Verify(pk, msg, sig, &Options{Context: "context"}); err != nil {
				b.Fatalf("Verify: %v", err)
			}
		}
	})

	// "Precomputed" runs only Verify with a pre-parsed public key.
	b.Run("Precomputed", func(b *testing.B) {
		pk, err := NewPublicKey(params, pub)
		if err != nil {
			b.Fatalf("NewPublicKey: %v", err)
		}
		for b.Loop() {
			if err := Verify(pk, msg, sig, &Options{Context: "context"}); err != nil {
				b.Fatalf("Verify: %v", err)
			}
		}
	})
}

func BenchmarkKeygen(b *testing.B) {
	b.Run("ML-DSA-44", func(b *testing.B) {
		for b.Loop() {
			NewPrivateKey(MLDSA44(), make([]byte, 32))
		}
	})
	b.Run("ML-DSA-65", func(b *testing.B) {
		for b.Loop() {
			NewPrivateKey(MLDSA65(), make([]byte, 32))
		}
	})
	b.Run("ML-DSA-87", func(b *testing.B) {
		for b.Loop() {
			NewPrivateKey(MLDSA87(), make([]byte, 32))
		}
	})
}

var benchmarkMessagesMLDSA44 = []string{
	"BUS7IAZWYOZ4JHJQYDWRTJL4V7",
	"MK5HFFNP4TB5S6FM4KUFZSIXPD",
	"DBFETUV4O56J57FXTXTIVCDIAR",
	"I4FCMZ7UNLYAE2VVPKTE5ETXKL",
	"56U76XRPOVFX3AU7MB2JHAP6JX",
	"3ER6UPKIIDGCXLGLPU7KI3ODTN",
	"JPQDX2IL3W5CYAFRZ4XUJOHQ3G",
	"6AJOEI33Z3MLEBVC2Q67AYWK5L",
	"WE3U36HYOPJ72RN3C74F6IOTTJ",
	"NMPF5I3B2BKQG5RK26LMPQECCX",
	"JRGAN2FA6IY7ESFGZ7PVI2RGWA",
	"UIKLF6KNSIUHIIVNRKNUFRNR4W",
	"HA252APFYUWHSZZFKP7CWGIBRY",
	"JFY774TXRITQ6CIR56P2ZOTOL6",
	"ZASYLW5Y3RAOC5NDZ2NCH5A4UY",
	"42X4JXNPXMFRCFAE5AKR7XTFO7",
	"YAHQUWUH534MUI2TYEKQR7VR3A",
	"HBP7FGEXGSOZ5HNOVRGXZJU2KG",
	"HG4O7DCRMYMQXASFLMYQ6NMIXK",
	"2KPQMDZKS65CLJU4DHTMVV5WI3",
	"G6YSUTEX4HHL44ISK2JVVK45BV",
	"PUJGPEQUBQM3IK2EXDQFJ2WGBG",
	"PNS6HMQAWA3RORSMSNEUAINMIR",
	"L35MZS4XYIJK453OFXCZG4WHIK",
	"CRY54YZMFRF6JTB3FPNNBWPUOG",
	"Y25TSZBWGU4HJCRMWZHAWXQ2DN",
	"23W64TW3AKZPKCM4HMKEHFI6VQ",
	"PWQAOZ24B4VLNEQR4XKN7LZHDI",
	"YINPDR3ZSAKPPXP6J6VAXHIPYO",
	"JDBB52ZRAB3PYBPNE7P4COY5PJ",
	"4DYU52LQLVG3LTREOTLBCJK3XC",
	"AB45MV6RKUGPCW4EUK7DX23MJX",
	"HEJSITE5K7J6YJ74OEATVTCERV",
	"ZKI5QCFCGM26UK7F5KYTENXKD2",
	"VH5G3ZLF5XC22QAEJ6JDGOBE5Y",
	"HYGXFHH3JW5SENG26MXLL54IGV",
	"MJUCRL36JZ757UYHBFPCJBPZRH",
	"IBH3T6NAVLCJQBYSVHAQFUITYA",
	"VMWCS7JMIMFQB6TPRAMOUXIKWD",
	"SXRPGPNNW2MMBKQS3HJURIQ3XV",
	"YPPYMJZW6WYXPSCZIPI57NTP5L",
	"N3SH6DUH6UOPU7YMQ6BJJEQSPI",
	"Q243DGA6VC6CW66FFUAB5V3VLB",
	"OUUBXEU4NJBRN5XZJ7YQUPIZLA",
	"H5TWHVGC7FXG6MCKJQURD3RNWG",
	"OONG2ZZ7H3P5BREEEURNJHBBQG",
	"HWROSSRTBCQOAIQAY5S4EQG4FX",
	"AJW6PW62JQNU72VKGIQMPBX64C",
	"OXECVUVAWBBBXGGQGQBTYVEP4S",
	"M5XN6V2LQJDEIN3G4Z6WJO6AVT",
	"NHGJUX3WGRTEIRPFWC2I467ST4",
	"SEOADTJDKAYYLDSC4VAES2CRDJ",
	"J5AT674S577ZFGEURNIAGYOHKW",
	"VJQVNMGHG4ITFX2XSPSDEWVZWD",
	"ZWY3KJPXTAVWWVHNAJDUXZ52TG",
	"HY46PBUGP4EMH34C6Q56MO7CJP",
	"MQTUO7CF6R6CRJPVV6F673M6VW",
	"35Z2Z5KV2RBJPQ7OZ24ZJE6BKR",
	"OVUEVXBLCU2BBY25QP5WJACDIX",
	"LNJX7PCLYL35WYJBW6CTXENPUU",
	"IH7E766LCENOQ5ZKZVCMLEPACU",
	"T2HZFGDDSFQ6YADB52NIFLBFEV",
	"RHQUJMN4MB5SYY4FP4ARZH52QJ",
	"W7GZC5ZM63UF2EJ7OC4WJM3OTH",
	"T2NHNFVOMICY33AQZSR53HXFQ6",
	"7ZVB4Y4K4Y2VAM5NC7HHAJNZIB",
	"UX2I4VF62XJGP2XTNN6LDKXTOH",
	"HJAMJR5RQTQW7JMW7ZLPRBZE7E",
	"HKWSKX7MB5346PHYNWNBAYDSYK",
	"BVWSB75HFLLE45MWA6EPHPTCFR",
	"YDH2J6NMM7UINHGUOPIUI7PSSR",
	"SYQPZLK52HMUAQFMVHGRJYKBEY",
	"7AA6UQFGSPBGNUDPLWXSGNKKPP",
	"AYXRJGRWZ5S3QOEDVWYHHCICHV",
	"KFJYAWO7IATSBCSTDUAA5EPFAN",
	"3JABTLB6T2ICHGVT3HXZZ3OAIT",
	"WCM3IBOCQJ36WSG627CCNK3QA7",
	"5FB5H3BZN2J4RGR2DUW7M37NKZ",
	"VKDDAD3BVOMPSNEDGIRHKX5S6R",
	"LFH5HVUR726OSFD3YVYM3ZHEIH",
	"Y4ETQB2KZVFB4M7SALLCTHX2FB",
	"E6SAU3C25MO2WBBVBKCKP2N4ZE",
	"3JA54Q3NEKURB5EAPL2FOFIESD",
	"FZPBW7BIQIW3FTKQD4TLKNWLMD",
	"LY5W6XFA2ZRI53FTUJYGWZ5RX6",
	"QID236JY3ICR55O5YRED33O7YT",
	"HDRU3L6MFEBCBQFNLF5IRPMOAL",
	"232ANKJBDBG4TSKQ7GJMWTHT23",
	"CDWE3CELZM5AOJGYEFHMUNSP5O",
	"7LNJRBOKN6W7RXUU34MDJ2SNKL",
	"S3IZOADTW2A6E5IGRO5WKX7FVH",
	"ZAISTLXC55EBMTN6KZ6QX5S7OS",
	"4Z5ZIVCMFR2PY2PY4Z47T4YPYA",
	"NE36L53Z6AMYQU7Q5REFUF76MK",
	"WND5UP5M6KWPBRFP5WIWTOWV3I",
	"7OC54DLFWMADJEMKEJ3Y2FMMZS",
	"BWJVZHGEN43ULNIOZCPZOB64HG",
	"VDFPQSR7RE54A75GT4JDZY5JK2",
	"HFCD5EPBZBSVMXIDA47DZ6MRD6",
	"RNBVFIUUJUM7EHRE3VNWSTORGO",
	"VO5NLQJBR22CRRYUETGTU6JLMR",
	"RZOMNFHBTL6HMGWH4PEEDASK7U",
	"QL73UBTOLK5O2TW43YWAIKS6T3",
	"NE3QVSMWS5G3W5C3BMKTJNMI2L",
	"YHI6EYQ4GZMB2QPGHPUG2ZUOEL",
	"6MBATW7MFNRUQBFD3GM35B7YPM",
	"AIYRY6P5T4XU44CGVPEV6W43FR",
	"MIAQ2FHXMAPY5NXSS45VRDPRMG",
	"2SNLHQYKK2K6NSWOF6KPGZ3CPC",
	"RVBHIQO5LH77ZWEAO3SVL72M2V",
	"XXTGJCJNRSNLE7ARAH2UU6LVKR",
	"DQMGILY5IDMWN5OYQYYXH26ZGR",
	"627VTXXMM455KMTFNUUTKNFXPY",
	"HC7IBFGLZCWGUR4K7REPMPW6W4",
	"CHL6JRQUS7D4NML3PFT37PPZAA",
	"Y767HXJAGJ75KE3JLO4DTLQIXC",
	"NTIODXI5I7TF2KXXWXOAYGT7G4",
	"PKZYEK2WAI4D4HEYYZH6H5IOMP",
	"FG6J6G7HZDEDF4JQBQOTC7RQGZ",
	"3VHM2VZU77Y25E3UUYZJLB2QLA",
	"WRZQJQW7ARH4DXYHVLCJ4HRTTB",
	"LQXKV5HD2AZHENSJ2VFLJ5YU5L",
	"MF6Q4OA2EN6TG6BUDK7RWCQNPU",
	"3USKYKPC5CB3EC4ZRMZVE3R2UO",
	"3WICO2GVS3IRBFUHNDLNKWVP7N",
	"P6ZR2UZZOVUZKT4KUS5WICW5XE",
	"PYPZUU76RYVOUZGUUX33HLDKYA",
	"2FTSURHV34VYTVIUU7W6V5C3NK",
	"YABDYMGXS2MD2CYF3S4ALG4FLG",
	"MHIBDH25RRPWV3P4VAWT6SAX3I",
	"OINSMWJQ2UTOOKZ3X6ICXXBQR7",
	"PFTQS7JNU2Q3Q6L4CGBXVLOYNE",
	"A4MZ7CCVYQUDJ2AFHNXBBQ3D24",
	"CPUB5R3ORTCMSMCLUQURE6AN5O",
	"NF5E7U3DFTXWFFXXHUXTEP4VZQ",
	"AWB5WDFERWSSJG53YGJMDORQKR",
	"U5JQUILKD6SEL6LXAMNFZP6VSW",
	"M45NLOAFLO74EJKG5EXNET6J5Y",
	"P2KTEUMZ5DZZMYSPOHDR2WJXAN",
	"KVO7AXZNFBUBPYLOTZQQ42TFNS",
	"WGJJ7SAEV6SBBWWYS4BTLD63WM",
	"Y6GURVDV4ESRBPWSTV25T4PE4K",
	"ESK7MPFPUZ5ZAQ52RP4SQIYCCC",
	"623M3CIABZ3RANERQ2IREXAVYO",
	"OQ4CQCFO42RS4BMMSGSDLUTOQO",
	"AMFHRDVGM6G2TIR3TKIFGFSDVM",
	"7VVSGGCVC53PLOYG7YHPFUJM5X",
	"Z3HMESVL7EZUSZNZ33WXEBHA2N",
	"AWWVRQD5W7IBSQPS26XOJVDV5H",
	"OQBZ5ZST3U3NZYHSIWRNROIG6L",
	"II573BW7DJLBYJSPSYIABQWDZD",
	"MOKXOQFOCUCLQQH4UKH2DPE7VN",
	"XR54NGUOU6BBUUTINNWBPJ35HX",
	"DNK36COZGFXI6DY7WLCNUETIRT",
	"R5M2PV7E3EHEM3TLGRCL3HSFMC",
	"ITKENZQYDQMZFCUPOT7VF3BMU7",
	"5GDCB74PPPHEP5N5G3DVRCYT7R",
	"ZMKXVRPLI5PY5BDVEPOA3NQZGN",
	"GBLIALWTHTUDTOMDERQFVB77CS",
	"VKRTTXUTFOK4PJAQQZCCT7TV3T",
	"ZJBUJJ4SW62BXOID3XO2W2M2PF",
	"SKWT5T6QJTCD3FCINIK22KMVBJ",
	"EHINNU6L33HRLOOJ3A2XFJSYQL",
	"N4HRQJEFPAT5SU3YPO74WSMQIR",
	"TGPTZ3ENMFWB5CZKJFR5WHIRI4",
	"O4HNFTAUJJ2LZPQXPXRAXOVABA",
	"4JVB5STP2YG5GYOXDWIF4KCKFB",
	"MY554X3YZHBECLHNNZ7A3SPJTU",
	"ASCJMAH7VCQAD2QJSWXPSVSM3H",
	"NBNGL5DZ623KCG2JNZFGZMZ7KD",
	"KGMZSW35AEQOJ6FA7IR7BHZI52",
	"Q7QUHHS4OJFMJ4I3FY6TDKSMZQ",
	"MZAE7TOEXAS76T7KIC73FEYRU4",
	"2BVESR3REAWADCGYOYM7T646RG",
	"EK3L2ORP4LT3HU3EMXDSQWFOKJ",
	"3X4A6VMGMIDLVK72FZSDHSERWY",
	"I3UHWI6M6HQFRBSQ6W2SABUNUP",
	"REKPXW4DIB4MTKMPHN3RBVHVME",
	"W37FNFZE35NX65Z7CVQ7L5U4L5",
	"4AGYK6U2KP6RAOADCBUDDCBECV",
	"IXM4SFQUDW2NOTXZIPWTNGET3F",
	"6YE4G3VELF27MN3Z5B4VIQ3XYK",
	"LPOZCPZAG3MD47MIWGR4FIOCDH",
	"WGREKUL2LD7C7SYGKH7APIY2A6",
	"WWW277FKTKUXQMP4BECSRHLWJI",
	"UYE4IQPMSTXVQG7EJALKWWEGDN",
	"TIV2L5Z6K7SNGNUVWSNKTAF4UE",
	"I3FQOAW3PINUK26P62HCX657FO",
}

var benchmarkMessagesMLDSA65 = []string{
	"NDGEUBUDWGRJJ3A4UNZZQOEKNL",
	"ACGYQUXN4POOFUENCLNCIPHFAZ",
	"Z3XETEYKROVJH7SIHOIAYCTO42",
	"DXWCVCEFULV7XHRWHJWSEXWES7",
	"BCR2D5PNLGFYX6B3QFQFV23JZP",
	"2DVP5HNG54ES64QK4D37PWUYTJ",
	"UJM4ADPJLURAIQH4XA6QYUGNJ6",
	"B5WRCIPK5IVZW52R6TJOKNPKZH",
	"7QNL6JTSP62IGX6RCM2NHRMTKK",
	"EJSZQYLM7G7AJCGIEVBV2UW7NN",
	"UFNA2NKJ3QFWNHHL5CXZ4R5H46",
	"QZAXRTT3E4DOGVTJCOTBG3WXQV",
	"KH2ETOYZO5UHIHIKATWJMUVG27",
	"V5HVVQTOWRXZ2PB4XWXSEKXUN5",
	"5LA7NAFI2LESMH533XY45QVCQW",
	"SMF4TWPTMJA2Z4F4OVETTLVRAY",
	"FWZ5OJAFMLTQRREPYF4VDRPPGI",
	"OK3QMNO3OZSKSR6Q4BFVOVRWTH",
	"NQOVN6F6AOBOEGMJTVMF67KTIJ",
	"CCLC4Y6YT3AQ3HGT2QNSYAUGNV",
	"CAZJHCHBUYQ6OKZ7DMWMDDLIZQ",
	"LVW5XDTHPKOW5D452SYD7AFO6Q",
	"EYA6O6FTYPC6TRKZPRPX5N2KQ4",
	"Z6SGAEZ2SAAZHPQO7GL7CUMBAG",
	"FKUCKW6JQVF4WQYXUSXYZQMAVY",
	"LN2KDF4DANPE4SC4GKJ4BES3IZ",
	"AVCRTWB6ALOQHY34XI7NTMP2JH",
	"A5WHIS6CBWPCYIEC6N2MBAOEZ6",
	"JC2BH476BXUQFIDA6UCR5V4G4F",
	"NU6XH6VLSSFHVSRZCYXPFYKYCD",
	"GSUXVZBDDYSZYFGXNP6AZW3PTC",
	"XJPRNJ26XP4MIYH2Q7M7MPZ73M",
	"INUTUP3IRFWIIT23DNFTIYKCFY",
	"T4KH7HKLEYGXHBIRFGFCRUZCC4",
	"GGQX4JFVWZHE5Y73YTLMSSOXNS",
	"BUA4Q3TQZGLVHMMJU62GQOSHLV",
	"WXW3SJXLSZO2MYF4YFIMXL2IQP",
	"Q32XBVVGFQTSXAIDJE6XSEPRZG",
	"6TEXT6SA7INRCTDSCSVZJEQ2YG",
	"ZBN4UL43C3SJIG4HYR236PXCVS",
	"TVWPLLC7NROBREWOM75VA3XCR3",
	"CCDGL2FURLBABQ4IJBYCB75JFR",
	"XBZGCOVTZHCPAARBTMAKPIE6GJ",
	"TPRAENJ7I54XRIVH6LL6FDIA3I",
	"RKOM3PHFILPIIQZL4ILQWGRYWI",
	"CEEZIZ2WUXHQQFATYYGQ3ZDBTI",
	"SLKOVAP6WLIVJBVU7VZG3ZGEOW",
	"TWMCLJJSWEEQQPQGGDKEJ5SU2R",
	"IFMUXXCD2LC7IGQLZ2QEK5UOQ2",
	"C7IWFEBHW2CXN4XBJS7VLWH3VK",
	"7KJYUEW3F264727TM4LE6RMGDO",
	"BPG2XAPBMBTA4VMPUM7IZVZPK3",
	"Y5X577BWRZNPLNUHJVSKGMUXYB",
	"ZCKMKM23E4IUPTNQDFN2LTLZVX",
	"4RKK223JNBDAP4G5DOAHHZ3VNO",
	"5UZ3TQZHZT22ISTB4WJEVO6MC4",
	"YMVS4HFSJ32CRZRL23PXZUEJFJ",
	"UQEUJUTPSZLZARNBXWMCTMHPFF",
	"CZAAZ5WK7EIPMW7NA3EZNNBF45",
	"227PBHH23WM7F2QLEZSPFYXVW4",
	"YUYS2J5CRFXZ4J4KJT2ZKIZVW3",
	"MFLHZJOZV44SN4AH6OJ3QZWM2O",
	"H2B3CRBCXYN7QWDGYUPHQZP23A",
	"T4L6YWQUQ3CTACENAJ5WUXZWFH",
	"N723H6MUGPZSRZ72C635OD4BP7",
	"NI4TUMVA6LQPQV2TXPN4QOIGBZ",
	"CQI3S4LSTQASSJJVZXEFPOVW7K",
	"ANPY4HJ64LLSB3GK2R4C6WDBS3",
	"RGWQCZKQLMT5FZRDE4B3VMASVK",
	"Q3WCCF2HA3CA4WWRJBMGBW7WI7",
	"2AKJRXFHXLUQPOXPTLSZN5PW4A",
	"IJWOOTI4N7RWXJIHAPXN6KEWEN",
	"4D53T6N6ATOVTD4LKSTAAWBJMU",
	"B4G5HDD6RITG6NIH6FXCRZDYZM",
	"TJCDFKMRUY2OG6KRSMNVCGQFUP",
	"PB33IHQKALAY6H6GVBVLI6ZRXK",
	"SCCWGW2J5S4WL4FTTMQ435F6DB",
	"ZVJH2HSMTLHGXMGPMXLJCKCLLE",
	"62LG37U6JXR77YRZQQCDSBHVCS",
	"BU4CBWOXQ352TEOKIXO245ID4O",
	"UEZOH7KEIODSEVRUF6GMWGA2RB",
	"IPJWROME4GM66CGLUWP5BJ4SX6",
	"355GDC7TG64AZJ7IJX6K62KZCZ",
	"AHTFKX3V7XUB3EWOMQVCGZYGUE",
	"N4RV2GKXJ4SPHHJ52Z7K5EGLER",
	"ZY7V7NE5F66XHDHWM6YNFEWZA6",
	"DIKFO5KAVT4WAP7BOEFM56ZUSR",
	"4TDFOFKDAPIOM3MU5GD7NPXNWQ",
	"AD7YZO756HDK6YWFILAKW3JWA7",
	"NUA53JS2ZK2BGHH3A7BJTJZYW7",
	"QLCNC3AQNKLRMSYR62WQSQP5VI",
	"SJ7OBS7ZYXSGXOYXPE5KW2XKN6",
	"44HBMOGMIMJS63CEXQU7FCXE2E",
	"KCK3J7ZL6QF4SLHHSWTJURK7PG",
	"HLH4CLUGBSOOBSS3BPO62N5MC3",
	"3FNS4GITO6OEUBAVDDXK4WOBTD",
	"IAC3K3I4AQGY3G6UHG7PL2N6TE",
	"KUKLNH74POJI5DYAEWUD7RABTQ",
	"ETM6N7VU3GBSQ7P5MCD6UF3E3S",
	"IZITM5NYBGJZLSI3BI4VEMW43U",
	"46OPQU4LL6N3Z2U7KYPKUMBAGI",
	"EV7YZ5DMAV7VKYJQUFSRD37GPP",
	"AV7W2PGYDJIAKLFVEBL6BXQSGC",
	"M2FOX5QZEZKV4QXKPI5XUZDHEM",
	"R4IFPLVMOVYCHRTR6LXAUGP3LL",
	"JGH6XJUMP4DRVAM27P2JNOKXVO",
	"D2XN3ZLLU6VFPMDYM7NBHSQEOI",
	"2PO3BYENOMQK6SHQDCFSRPJQI3",
	"IBVQ7U3QEUC6PQRE4PV53JTZTK",
	"ZBCOX4P7NG2IXXFB2R43MG2SLV",
	"5NJDPQVVDO7ADNZ2CV7L6QBNGZ",
	"V7ASFIIYUMXFGW4B7ZM6LOGUTE",
	"PX5IJZ7W2LUPKM6YN4PMZ43ZLM",
	"AYK7SZ23DHC7Q56MWAJXBG76LB",
	"UYCAPXJM4HNGKLIDSZ4NCEDJLN",
	"UWMDZ3C2ODLACKGJPGETNQ3TA4",
	"Q6OI6R3WYYJ4CCZCDJBQMCRCZR",
	"LCMJHLP7354APCEGPKE7HHWTWB",
	"N7T7ZKOYPAMEYTTDOWZNCN6PRD",
	"UZADPU4UNHAF7L7LQDMTKA2EQH",
	"DC2OEPQDECVLRVNNCS6BMH4CRA",
	"37IZ427XHUMZ66EJ62U2YEZDAC",
	"6BCZDQZDPZLS5OGESKNUBPSSFV",
	"ST2LEMJ4OLQ32TJTLH2WCWT4WA",
	"GA2TL4SFLEW4G2B5PQMIKJT5XG",
	"L7PPBIET26EH7LQTLEFC4I4EIA",
	"6YSM7MC2W4DEV6ULAHMX27LH56",
	"QL26Z5KZ4YRRG2BXXGDRRLV357",
	"677TWRAJ5NSNHCE243POQPEG7K",
	"66MEBQJLGAGVXDX3KZ2YFTTVJM",
	"6D4VUWAQD6R65ICSDLFAATC67V",
	"7GXLD5CNU3TDUQSSW42SHL7B5D",
	"RQETUMEBG2ZM2NF2EZAQHGHWWE",
	"DCRX5ANWDMXZFIDVAXYLQZYMRN",
	"5SDWT7YAF7L4WWANAGYINZAYXH",
	"PZILRV7I2S6WKUSHKYRLA2JQY3",
	"2G66TK2PZ5MOTAZDN7BFS3LAIH",
	"QOLJ3WGJ6JS3FMMXBNTNAIKXVK",
	"FMAL67YTHDCCYVZ5CRMN2XJPDN",
	"UOTZDXTJKQ3YAIRKHTYNX6G55P",
	"X3DLNPJ3V62LRHGEY4DTT35H3R",
	"DKU7CHNXPB5QRZVGIQZW46XCKC",
	"RAKBD4LQKEDTVDSK3DVTRWG23B",
	"INTRA7BWHLVQMBRKBJNUSMF7MU",
	"AUYRBNVCOYYHOHUYOOFIZ2FWMD",
	"22EJVDEQ7PASLBAMTVKXOQP5RJ",
	"3S6NATWA57SFTZEW7UZUOUYAEU",
}

var benchmarkMessagesMLDSA87 = []string{
	"LQQPGPNUME6QDNDTQTS4BA7I7M",
	"PTYEEJ7RMI6MXNN6PZH222Y6QI",
	"R6DTHAADKNMEADDK5ECPNOTOAT",
	"S2QM7VDC6UKRQNRETZMNAZ6SJT",
	"EYULPTSJORQJCNYNYVHDFN4N3F",
	"YETZNHZ75SXFU672VQ5WXYEPV2",
	"KTSND3JGA4AN3PCMG4455JEXGR",
	"JGE6HK37O6XMWZQZCHFUPNUEXP",
	"CRYB2FZD2BYNANBFFO2HRZEHGZ",
	"7MLNDZJ7OIEPBJZOMULOMQH2BA",
	"4WQCNTIFVSX2DNALMWUKZRA6CI",
	"Y5NK4OBDSDWC5WLL27CEEXYYOT",
	"C4SSWSPBVCDAWJXH2CDMXR36LH",
	"THDBKXRTKWJUGJMAAYTWTFMX7Z",
	"NWXPUD4DAA6QOREW4AFFYQYQNG",
	"3RQIJXMO7WYHBEBL3G6EOLNZNQ",
	"R7JEOHFP2C7O4AVPRPRELXWOMM",
	"LU6MWR7SZXVIKS54BY62X67NPA",
	"FG2FFM4F2ECKHCSJ75KXK632JP",
	"BF76ZDSVVUSYS5KK4FFD22YPS7",
	"HCLBWZRLHEMYZLFWHLAN2BKCZ7",
	"HGFVS4QC7AWXYPVRSWAK77KTQF",
	"LUZ3C53PUUHBWCDJ7WAHK2UT3K",
	"Y3WR6SMDUBW34N3MUT7EQYIJCV",
	"F2X35AQTXVZBMPXTWNAAH4ZX2W",
	"6MKFFDYWD6ZAKS3C6GRCRLZLRF",
	"AFMZYYFRHKMQRNKU5UTSKQ74H6",
	"TDTN7J3O367OVPWLESRNPLN4M2",
	"WYMLD2X6N4CZ2RDOKF5CFTSYTG",
	"UNPTSBLJ6HZRNR72T2VEEHCFX2",
	"SNCM4R2P27AJOXBS67RMCARS3U",
	"OU7QBE5QOXO7CIYTBJR3KOW2WK",
	"2NNQOBQKZ2OD4ZAXI3SNEURYUP",
	"YQTUPOYBT67XPCHIGKSGSKC3BZ",
	"HGB4ZM3G76IXYWWCMVT3HONRIS",
	"WZC6QUKRZZ2TOVA277JYKQITEW",
	"XO2WT46A5HYL6CUJF7SGJ6YWOG",
	"4QJA35PMYQIDRZ7ZHG7RLZJVGF",
	"BMJZELWZ4I2UWXESU3NR6ATC4M",
	"XWLFB7FN6D5PRY6YUXC5JUIBFM",
	"WRAFFF27AVTIOYIBYA2IPTXI3R",
	"VOXUTYTN2XZ362OJFO2R53UCUF",
	"UHN73ARJ737WUJ6QYEI7U46OPO",
	"3Y3K5E2A4ML3VYVNAFWEEIXTSN",
	"QMU4322NKPRLE7JBGYFGS36H2S",
	"NJAQTNCXPVDICTDVUKTPRCD2AX",
	"OC373ZFBNV2H46T6OY3XRPSUHG",
	"UBLAS6CDWE3A662MLKP7QDEOCC",
	"BKFDLAL2RTPMERYVW3B7UJ5W3H",
	"QFKFGXKGW5SAKLBAWQXUWW77OS",
	"EJNUQHTLLOVB4ARETOGLY4WUTJ",
	"N243OCMVLLAO6I2XLCYOIMQYGY",
	"YRRFLWK7ZASUKYX7ZLQMW2PJ6X",
	"3DGVPBWD2BIK6KQE65K72DNJNM",
	"TJRYMNOAIW33VIHKLJG4GXAVUK",
	"6DSRINAYXL34U54U355U7IVFGS",
	"6CHA4MX7LVS77XKRWG7IYC3XVL",
	"GM2CEGBEPBOHAPIOBUWJ4MJNTG",
	"VJKHGBY33VUIJFEQLX3JVUNQBD",
	"DTOHAD5M2KL46IZHE4TPLJWHTI",
	"IYFG3UDN7ROOY2ZFSLM2BU2LMQ",
	"A5OGJHPOE4PW6QSZYHZ5TKPGIC",
	"FX4BCN67AEGCLUTLFPNDL3SQU5",
	"MWIZQVOZOHTTBUXC3BEX62MNI5",
	"BYHVJHBLK4O6LFSKEIQ3CAAKU7",
	"QJU7P6KWSSKAA5GVA6RH4OV7MX",
	"I3T3XM5Z5TAJHAYDQHFA2ZV7PU",
	"L46MQCHV3TJ6FYIQQ2FCJXES74",
	"QXZRQIYAJMXYR6PU3VDYGCIT5W",
	"MFS53RR2XEYS22NYOJLGTHVTTM",
	"FRWIWJRP4AQMXWX4WJ4WYVKM3E",
	"X6GK6IGVLJWYSHLKHGXSW3TJDP",
	"L5LPJ2HIWA4UY6G6FMZXGDEDAM",
	"GD6FYOYUGDHXEQ5S2KLJEGNSN7",
	"ODAL7ZRKXSPAAN5DVRBWJQCFQX",
	"CV3QFBDXBPT3SCPJGUYSMDN6ZS",
	"IGSLSACRZ6XID466KQIB4YNGYO",
	"WZ2EACBN26RAML2S52YXRYP2OF",
	"LB76VEVNOBYFMKFZ7SDFCBCHQE",
	"TLFA7EU3JJFAP6EMUKNV2ZXRBM",
	"SIIJF6OXAKRP25CBUYFBRCDDVP",
	"TEPNI7TJ7HASJWIQMBS4VFLRQC",
	"VK2JINYWEDV7IQFWH4OTAD4W5O",
	"GILUH5AMVE4TM7EKPXJBZGT6EJ",
	"DV7ALFRAW3TI4WMQQLDTO6RNHN",
	"CAIB5G3NXC5ASPLFIWAFPVHS5B",
	"MLFJXZUOAGN7EGPMXOOVTB2CL4",
	"6MZYT3ANWHBOS67WGHZI3QPEAP",
	"LVJDQB52C2PERSSQJRMRCJ4UBF",
	"QY4VKAZAYQIZOX2L2VO2QHAQVC",
	"UAA5SST2XA76JPKM3XOZ5RUHFI",
	"VLZWF53JSQ6SCRUFDKVPXWAS4L",
	"NX2DZIKMJIYXUNSAHFP23FHTBU",
	"F5OAKDDDA34A2RPIKDPM5CYPMZ",
	"E5PEP3ANIK2L4VLOST4NIYNKBD",
	"IPBGFLHSMP4UFXF6XJX42T6CAL",
	"XHPU7DBFTZB2TX5K34AD6DJTK3",
	"2ZU7EJN2DG2UMT6HX5KGS2RFT6",
	"SD5S7U34WSE4GBPKVDUDZLBIEH",
	"WZFFL3BTQAV4VQMSAGCS45SGG3",
	"QE7ZT2LI4CA5DLSVMHV6CP3E3V",
	"YIWMS6AS72Z5N2ALZNFGCYC5QL",
	"A4QJ5FNY54THAKBOB65K2JBIV7",
	"6LORQGA3QO7TNADHEIINQZEE26",
	"5V45M6RAKOZDMONYY4DIH3ZBL2",
	"SVP7UYIZ5RTLWRKFLCWHAQV3Y2",
	"C2UYQL2BBE4VLUJ3IFNFMHAN7O",
	"P4DS44LGP2ERZB3OB7JISQKBXA",
	"A6B4O5MWALOEHLILSVDOIXHQ4Z",
	"DKQJTW5QF7KDZA3IR4X5R5F3CG",
	"H6QFQX2C2QTH3YKEOO57SQS23J",
	"DIF373ML2RWZMEOIVUHFXKUG7O",
	"Z5PPIA3GJ74QXFFCOSUAQMN5YN",
	"PM6XIDECSS5S77UXMB55VZHZSE",
}
