util/fipstools/acvp/acvptool/subprocess/eddsa.go (279 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC package subprocess import ( "encoding/json" "fmt" "strings" "boringssl.googlesource.com/boringssl/util/fipstools/acvp/acvptool/katemitter" ) // NIST ACVP EDDSA Schema: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html type eddsa struct{} func (e *eddsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { var vs struct { Mode string `json:"mode"` TestGroups json.RawMessage `json:"testGroups"` } if err := json.Unmarshal(vectorSet, &vs); err != nil { return nil, err } var processTestGroups func(json.RawMessage, Transactable) (interface{}, error) switch { case strings.EqualFold(vs.Mode, "keyGen"): processTestGroups = processEddsaKeyGenTestGroup case strings.EqualFold(vs.Mode, "keyVer"): processTestGroups = processEddsaKeyVerTestGroup case strings.EqualFold(vs.Mode, "sigGen"): processTestGroups = processEddsaSigGenTestGroup case strings.EqualFold(vs.Mode, "sigVer"): processTestGroups = processEddsaSigVerTestGroup default: return nil, fmt.Errorf("unsupported EDDSA mode %q", vs.Mode) } return processTestGroups(vs.TestGroups, m) } func processEddsaKeyGenTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { var groups []eddsaKeyGenTestGroup if err := json.Unmarshal(testGroups, &groups); err != nil { return nil, err } var ret []eddsaKeyGenTestGroupResponse for _, group := range groups { response := eddsaKeyGenTestGroupResponse{ ID: group.ID, } if group.Type != "AFT" { return nil, fmt.Errorf("unsupported test type %q", group.Type) } for _, test := range group.Tests { result, err := m.Transact("EDDSA/"+string(group.Curve)+"/keyGen", 2) if err != nil { return nil, err } response.Tests = append(response.Tests, eddsaKeyGenTestCaseResponse{ ID: test.ID, D: result[0], Q: result[1], }) } ret = append(ret, response) } return ret, nil } func processEddsaKeyVerTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { var groups []eddsaKeyVerTestGroup if err := json.Unmarshal(testGroups, &groups); err != nil { return nil, err } var ret []eddsaKeyVerTestGroupResponse for _, group := range groups { if group.Type != "AFT" { return nil, fmt.Errorf("unsupported test type %q", group.Type) } response := eddsaKeyVerTestGroupResponse{ ID: group.ID, } for _, test := range group.Tests { results, err := m.Transact("EDDSA/"+string(group.Curve)+"/keyVer", 1, test.Q) if err != nil { return nil, err } var passed *bool if len(results[0]) == 1 { val := results[0][0] == 1 passed = &val } response.Tests = append(response.Tests, eddsaKeyVerTestCaseResponse{ ID: test.ID, Passed: passed, }) } ret = append(ret, response) } return ret, nil } func processEddsaSigGenTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { var groups []eddsaSigGenTestGroup if err := json.Unmarshal(testGroups, &groups); err != nil { return nil, err } var ret []eddsaSigGenTestGroupResponse for _, group := range groups { if group.Type != "AFT" && group.Type != "BFT" { return nil, fmt.Errorf("unsupported test type %q", group.Type) } if group.Prehash { katemitter.NewSection(fmt.Sprintf("HashEdDSA %s %s", group.Curve, group.Type)) } else { katemitter.NewSection(fmt.Sprintf("EdDSA %s %s", group.Curve, group.Type)) } results, err := m.Transact("EDDSA/"+string(group.Curve)+"/keyGen", 2) if err != nil { return nil, err } seed := results[0] q := results[1] response := eddsaSigGenTestGroupResponse{ ID: group.ID, Q: q, } for _, test := range group.Tests { command := "EDDSA/" + string(group.Curve) + "/sigGen" args := [][]byte{seed, test.Message} if group.Prehash { if test.ContextLength != len(test.Context) { return nil, fmt.Errorf("mismatch between context and contextLength, %v != %v", test.ContextLength, len(test.Context)) } command += "/preHash" args = append(args, test.Context) } results, err := m.Transact(command, 1, args...) if err != nil { return nil, err } signature := results[0] response.Tests = append(response.Tests, eddsaSigGenTestCaseResponse{ ID: test.ID, Signature: signature, }) emitSigGenKatTestCase(test.ID, seed, q, test.Message, test.Context, signature) } ret = append(ret, response) } return ret, nil } func processEddsaSigVerTestGroup(testGroups json.RawMessage, m Transactable) (interface{}, error) { var groups []eddsaSigVerTestGroup if err := json.Unmarshal(testGroups, &groups); err != nil { return nil, err } var ret []eddsaSigVerTestGroupResponse for _, group := range groups { if group.Type != "AFT" { return nil, fmt.Errorf("unsupported test type %q", group.Type) } response := eddsaSigVerTestGroupResponse{ ID: group.ID, } for _, test := range group.Tests { command := "EDDSA/" + string(group.Curve) + "/sigVer" args := [][]byte{test.Message, test.Q, test.Signature} if group.Prehash { command += "/preHash" // ACVP sigVer supports HashEdDSA/PreHash but doesn't list context as given in the schema? // Assuming an empty context here for now until the schema changes... args = append(args, []byte{}) } results, err := m.Transact(command, 1, args...) if err != nil { return nil, err } var passed *bool if len(results[0]) == 1 { val := results[0][0] == 1 passed = &val } response.Tests = append(response.Tests, eddsaSigVerTestCaseResponse{ ID: test.ID, Passed: passed, }) } ret = append(ret, response) } return ret, nil } const Ed25519 EDDSACurve = "ED-25519" type EDDSACurve string func (e *EDDSACurve) UnmarshalJSON(v []byte) error { var str string if err := json.Unmarshal(v, &str); err != nil { return err } switch { case strings.EqualFold(str, "ED-25519"): *e = Ed25519 default: return fmt.Errorf("unsupported EDDSA curve: %q", str) } return nil } type eddsaKeyGenTestGroup struct { ID uint64 `json:"tgId"` Curve EDDSACurve `json:"curve"` Type string `json:"testType"` Tests []struct { ID uint64 `json:"tcId"` } } type eddsaKeyVerTestGroup struct { ID uint64 `json:"tgId"` Curve EDDSACurve `json:"curve"` Type string `json:"testType"` Tests []struct { ID uint64 `json:"tcId"` Q hexEncodedByteString `json:"q"` } } type eddsaSigGenTestGroup struct { ID uint64 `json:"tgId"` Curve EDDSACurve `json:"curve"` Prehash bool `json:"prehash"` Type string `json:"testType"` Tests []struct { ID uint64 `json:"tcId"` Message hexEncodedByteString `json:"message"` Context hexEncodedByteString `json:"context"` ContextLength int `json:"contextLength"` } } type eddsaSigVerTestGroup struct { ID uint64 `json:"tgId"` Curve EDDSACurve `json:"curve"` Prehash bool `json:"prehash"` Type string `json:"testType"` Tests []struct { ID uint64 `json:"tcId"` Message hexEncodedByteString `json:"message"` Q hexEncodedByteString `json:"q"` Signature hexEncodedByteString `json:"signature"` } } type eddsaKeyGenTestGroupResponse struct { ID uint64 `json:"tgId"` Tests []eddsaKeyGenTestCaseResponse `json:"tests"` } type eddsaKeyGenTestCaseResponse struct { ID uint64 `json:"tcId"` D hexEncodedByteString `json:"d"` Q hexEncodedByteString `json:"q"` } type eddsaKeyVerTestGroupResponse struct { ID uint64 `json:"tgId"` Tests []eddsaKeyVerTestCaseResponse `json:"tests"` } type eddsaKeyVerTestCaseResponse struct { ID uint64 `json:"tcId"` Passed *bool `json:"testPassed"` } type eddsaSigGenTestGroupResponse struct { ID uint64 `json:"tgId"` Q hexEncodedByteString `json:"q"` Tests []eddsaSigGenTestCaseResponse `json:"tests"` } type eddsaSigGenTestCaseResponse struct { ID uint64 `json:"tcId"` Signature hexEncodedByteString `json:"signature"` } type eddsaSigVerTestGroupResponse struct { ID uint64 `json:"tgId"` Tests []eddsaSigVerTestCaseResponse `json:"tests"` } type eddsaSigVerTestCaseResponse struct { ID uint64 `json:"tcId"` Passed *bool `json:"testPassed"` } func emitSigGenKatTestCase(id uint64, seed, q, message, context, signature []byte) { katemitter.NewTestCase(fmt.Sprintf("%d", id)) katemitter.WriteBytesKvPair("SEED", seed) katemitter.WriteBytesKvPair("Q", q) katemitter.WriteBytesKvPair("MESSAGE", message) if len(context) > 0 { katemitter.WriteBytesKvPair("CONTEXT", context) } katemitter.WriteBytesKvPair("SIGNATURE", signature) }