crypto/mldsa: remove hand-defined wycheproof structs Take a temporary replace directive in the go.mod for the crypto/internal/cryptotest/wycheproof/_schema go.mod on a yet-to-be-merged upstream fix to atombender/go-jsonschema. This fixes a limitation where schemas with certain unmodelled properties (e.g. conditional validation requirements) would result in the generated code using a generic interface type instead of a structure. With this in place the ML-DSA wycheproof test can lose its manually defined structure + unmarshalling code in favour of using the generated structure type that's always in-sync with upstream. Change-Id: Ibbd7b41aaa0caf6414b319b77e62762b498ed6f8 Reviewed-on: https://go-review.googlesource.com/c/go/+/795301 Reviewed-by: Filippo Valsorda <filippo@golang.org> Auto-Submit: Daniel McCarney <daniel@binaryparadox.net> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Hongxiang Jiang <hxjiang@golang.org>
diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod b/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod index a94ecb8..1253c1c 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod
@@ -15,3 +15,5 @@ github.com/sanity-io/litter v1.5.8 // indirect github.com/sosodev/duration v1.4.0 // indirect ) + +replace github.com/atombender/go-jsonschema => github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31
diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum b/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum index 06b458e..bc5fe4e 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum
@@ -1,12 +1,12 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -github.com/atombender/go-jsonschema v0.23.1 h1:hpj94ehS+gpVvd1NJSTE0BMtWIpab06ObCz57rwo37c= -github.com/atombender/go-jsonschema v0.23.1/go.mod h1:4SrgNrwGKijxhewvpPQ8HKEbin5Q2N4Tk+pFKW77HEk= github.com/c2sp/wycheproof v0.0.0-20260606153636-6d7cccd0fcb1 h1:veaGluF2y7kZnV/owZzY3FuOZWZQdzqnIcJsbJpFV7A= github.com/c2sp/wycheproof v0.0.0-20260606153636-6d7cccd0fcb1/go.mod h1:/5JsOpi3fKmnnig5BQ2mz49TNtnrD308VfTVHcbr5x4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31 h1:c2W1mlsq9K/W+GPQWycHmGxTq4/RkWgDHOY99K+rtaw= +github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31/go.mod h1:4SrgNrwGKijxhewvpPQ8HKEbin5Q2N4Tk+pFKW77HEk= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
diff --git a/src/crypto/internal/cryptotest/wycheproof/schema.go b/src/crypto/internal/cryptotest/wycheproof/schema.go index b0a5459..50c655f 100644 --- a/src/crypto/internal/cryptotest/wycheproof/schema.go +++ b/src/crypto/internal/cryptotest/wycheproof/schema.go
@@ -6170,7 +6170,67 @@ return nil } -type MlDsaSignTestVector interface{} +type MlDsaSignTestVector struct { + // A brief description of the test case + Comment string `json:"comment"` + + // [optional] The additional context string (if omitted, the context input is + // empty) + Ctx *string `json:"ctx,omitempty,omitzero"` + + // A list of flags + Flags []string `json:"flags"` + + // [optional] The message to sign (if omitted, mu is provided to use with + // Sign_internal) + Msg *string `json:"msg,omitempty,omitzero"` + + // [optional] The 64-byte μ value (omitted in case of expected failure) + Mu *string `json:"mu,omitempty,omitzero"` + + // Result corresponds to the JSON schema field "result". + Result Result `json:"result"` + + // [optional] The 32-byte random value (if omitted, implicitly all zeroes for + // deterministic signing) + Rnd *string `json:"rnd,omitempty,omitzero"` + + // The encoded signature (empty in case of expected failure) + Sig string `json:"sig"` + + // Identifier of the test case + TcId int `json:"tcId"` +} + +// UnmarshalJSON implements json.Unmarshaler. +func (j *MlDsaSignTestVector) UnmarshalJSON(value []byte) error { + var raw map[string]interface{} + if err := json.Unmarshal(value, &raw); err != nil { + return err + } + if _, ok := raw["comment"]; raw != nil && !ok { + return fmt.Errorf("field comment in MlDsaSignTestVector: required") + } + if _, ok := raw["flags"]; raw != nil && !ok { + return fmt.Errorf("field flags in MlDsaSignTestVector: required") + } + if _, ok := raw["result"]; raw != nil && !ok { + return fmt.Errorf("field result in MlDsaSignTestVector: required") + } + if _, ok := raw["sig"]; raw != nil && !ok { + return fmt.Errorf("field sig in MlDsaSignTestVector: required") + } + if _, ok := raw["tcId"]; raw != nil && !ok { + return fmt.Errorf("field tcId in MlDsaSignTestVector: required") + } + type Plain MlDsaSignTestVector + var plain Plain + if err := json.Unmarshal(value, &plain); err != nil { + return err + } + *j = MlDsaSignTestVector(plain) + return nil +} type MlDsaVerifyTestGroup struct { // Encoded ML-DSA public key
diff --git a/src/crypto/mldsa/mldsa_wycheproof_test.go b/src/crypto/mldsa/mldsa_wycheproof_test.go index 8abef04..9a5bcd3 100644 --- a/src/crypto/mldsa/mldsa_wycheproof_test.go +++ b/src/crypto/mldsa/mldsa_wycheproof_test.go
@@ -12,7 +12,6 @@ "crypto/internal/cryptotest/wycheproof" internalmldsa "crypto/internal/fips140/mldsa" "crypto/mldsa" - "encoding/json" "slices" "testing" ) @@ -95,9 +94,7 @@ expectedPublicKey = wycheproof.MustDecodeHex(pk) } - for _, raw := range tg.Tests { - tv := decodeMLDSASignTestVector(t, raw) - + for _, tv := range tg.Tests { t.Run(wycheproof.TestName(file, tv), func(t *testing.T) { t.Parallel() @@ -128,7 +125,7 @@ } } -func runSignTest(t *testing.T, priv *mldsa.PrivateKey, tv mldsaSignTestVector, shouldPass bool) { +func runSignTest(t *testing.T, priv *mldsa.PrivateKey, tv wycheproof.MlDsaSignTestVector, shouldPass bool) { t.Helper() var msg, μ []byte @@ -213,9 +210,7 @@ expectedPublicKey = wycheproof.MustDecodeHex(pk) } - for _, raw := range tg.Tests { - tv := decodeMLDSASignTestVector(t, raw) - + for _, tv := range tg.Tests { t.Run(wycheproof.TestName(file, tv), func(t *testing.T) { t.Parallel() @@ -242,7 +237,7 @@ } } -func runRandomizedSignTest(t *testing.T, priv *internalmldsa.PrivateKey, tv mldsaSignTestVector, shouldPass bool) { +func runRandomizedSignTest(t *testing.T, priv *internalmldsa.PrivateKey, tv wycheproof.MlDsaSignTestVector, shouldPass bool) { t.Helper() var msg, μ []byte @@ -334,8 +329,7 @@ expectedPublicKey = wycheproof.MustDecodeHex(pk) } - for _, raw := range tg.Tests { - tv := decodeMLDSASignTestVector(t, raw) + for _, tv := range tg.Tests { t.Run(wycheproof.TestName(file, tv), func(t *testing.T) { t.Parallel() @@ -381,34 +375,3 @@ t.Fatalf("unknown algorithm: %s", algorithm) return nil } - -// mldsaSignTestVector is a typed view of wycheproof.MlDsaSignTestVector, -// which the schema generator emits as interface{} because of the schema's -// conditional clauses. -type mldsaSignTestVector struct { - TcId int `json:"tcId"` - Comment string `json:"comment"` - Msg *string `json:"msg,omitempty"` - Ctx *string `json:"ctx,omitempty"` - Mu *string `json:"mu,omitempty"` - Rnd *string `json:"rnd,omitempty"` - Sig string `json:"sig"` - Result wycheproof.Result `json:"result"` - Flags []string `json:"flags"` -} - -// decodeMLDSASignTestVector roundtrips an interface{} typed raw -// MlDsaSignTestVector to produce a typed MLDSASignTestVector. -// This is a workaround for a limitation of the schema generator. -func decodeMLDSASignTestVector(t *testing.T, raw wycheproof.MlDsaSignTestVector) mldsaSignTestVector { - t.Helper() - b, err := json.Marshal(raw) - if err != nil { - t.Fatalf("re-marshal sign test vector: %v", err) - } - var tv mldsaSignTestVector - if err := json.Unmarshal(b, &tv); err != nil { - t.Fatalf("decode sign test vector: %v", err) - } - return tv -}