@@ -593,6 +593,154 @@ func TestInvalidSize(t *testing.T) {
593593 }
594594}
595595
596+ func TestUninitialized (t * testing.T ) {
597+ t .Run ("Verify" , func (t * testing.T ) {
598+ msg := []byte ("attacker-controlled message" )
599+ sig := make ([]byte , MLDSA44SignatureSize )
600+
601+ cases := []struct {
602+ name string
603+ fn func () error
604+ }{
605+ {"empty signature/nil opts" , func () error {
606+ var pk PublicKey
607+ return Verify (& pk , msg , nil , nil )
608+ }},
609+ {"empty signature/empty opts" , func () error {
610+ var pk PublicKey
611+ return Verify (& pk , msg , nil , & Options {})
612+ }},
613+ {"zero length signature" , func () error {
614+ var pk PublicKey
615+ return Verify (& pk , msg , []byte {}, nil )
616+ }},
617+ {"full length signature" , func () error {
618+ var pk PublicKey
619+ return Verify (& pk , msg , sig , nil )
620+ }},
621+ {"full length signature/with context" , func () error {
622+ var pk PublicKey
623+ return Verify (& pk , msg , sig , & Options {Context : "ctx" })
624+ }},
625+ }
626+ for _ , c := range cases {
627+ t .Run (c .name , func (t * testing.T ) {
628+ err , panicked := call (c .fn )
629+ if panicked != nil {
630+ t .Errorf ("Verify panicked: %v" , panicked )
631+ }
632+ if err == nil {
633+ t .Error ("Verify accepted uninitialized PublicKey, want error" )
634+ }
635+ })
636+ }
637+ })
638+
639+ signFuncs := []struct {
640+ name string
641+ sign func (sk * PrivateKey , msg []byte , opts crypto.SignerOpts ) ([]byte , error )
642+ }{
643+ {"Sign" , func (sk * PrivateKey , msg []byte , opts crypto.SignerOpts ) ([]byte , error ) {
644+ return sk .Sign (nil , msg , opts )
645+ }},
646+ {"SignDeterministic" , func (sk * PrivateKey , msg []byte , opts crypto.SignerOpts ) ([]byte , error ) {
647+ return sk .SignDeterministic (msg , opts )
648+ }},
649+ }
650+ for _ , f := range signFuncs {
651+ t .Run (f .name , func (t * testing.T ) {
652+ msg := []byte ("message" )
653+
654+ cases := []struct {
655+ name string
656+ fn func () error
657+ }{
658+ {"nil opts" , func () error {
659+ var sk PrivateKey
660+ _ , err := sk .Sign (nil , msg , nil )
661+ return err
662+ }},
663+ {"empty opts" , func () error {
664+ var sk PrivateKey
665+ _ , err := sk .Sign (nil , msg , & Options {})
666+ return err
667+ }},
668+ {"typed nil opts" , func () error {
669+ var sk PrivateKey
670+ _ , err := sk .Sign (nil , msg , (* Options )(nil ))
671+ return err
672+ }},
673+ {"mu opts" , func () error {
674+ var sk PrivateKey
675+ _ , err := sk .Sign (nil , msg , muOptions {})
676+ return err
677+ }},
678+ }
679+ for _ , c := range cases {
680+ t .Run (c .name , func (t * testing.T ) {
681+ err , panicked := call (c .fn )
682+ if panicked != nil {
683+ t .Errorf ("panicked: %v" , panicked )
684+ }
685+ if err == nil {
686+ t .Error ("accepted zero-value PrivateKey, want error" )
687+ }
688+ })
689+ }
690+ })
691+ }
692+
693+ t .Run ("TypedNilOptions" , func (t * testing.T ) {
694+ sk , err := GenerateKey (MLDSA44 ())
695+ if err != nil {
696+ t .Fatal (err )
697+ }
698+ msg := []byte ("message" )
699+
700+ t .Run ("SignDeterministic" , func (t * testing.T ) {
701+ want , err := sk .SignDeterministic (msg , nil )
702+ if err != nil {
703+ t .Fatalf ("SignDeterministic(nil opts): %v" , err )
704+ }
705+ var got []byte
706+ _ , panicked := call (func () (err error ) {
707+ got , err = sk .SignDeterministic (msg , (* Options )(nil ))
708+ return err
709+ })
710+ if panicked != nil {
711+ t .Fatalf ("SignDeterministic(typed-nil opts) panicked: %v" , panicked )
712+ }
713+ if ! bytes .Equal (got , want ) {
714+ t .Error ("SignDeterministic(typed-nil opts) != SignDeterministic(nil opts)" )
715+ }
716+ })
717+
718+ t .Run ("Sign" , func (t * testing.T ) {
719+ var sig []byte
720+ _ , panicked := call (func () (err error ) {
721+ sig , err = sk .Sign (nil , msg , (* Options )(nil ))
722+ return err
723+ })
724+ if panicked != nil {
725+ t .Fatalf ("Sign(typed-nil opts) panicked: %v" , panicked )
726+ }
727+ if err := Verify (sk .PublicKey (), msg , sig , nil ); err != nil {
728+ t .Errorf ("signature made with typed-nil opts does not verify under empty context: %v" , err )
729+ }
730+ })
731+ })
732+ }
733+
734+ func call (fn func () error ) (err error , panicked any ) {
735+ defer func () { panicked = recover () }()
736+ err = fn ()
737+ return err , nil
738+ }
739+
740+ type muOptions struct {}
741+
742+ func (muOptions ) HashFunc () crypto.Hash { return crypto .MLDSAMu }
743+
596744func BenchmarkSign (b * testing.B ) {
597745 // Signing works by rejection sampling, which introduces massive variance in
598746 // individual signing times. To get stable but correct results, we benchmark
0 commit comments