|  | package subprocess | 
|  |  | 
|  | import ( | 
|  | "encoding/hex" | 
|  | "encoding/json" | 
|  | "fmt" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | // Common top-level structure to parse mode | 
|  | type mlkemTestVectorSet struct { | 
|  | Algorithm string `json:"algorithm"` | 
|  | Mode      string `json:"mode"` | 
|  | Revision  string `json:"revision"` | 
|  | } | 
|  |  | 
|  | // Key generation specific structures | 
|  | type mlkemKeyGenTestVectorSet struct { | 
|  | Algorithm string                 `json:"algorithm"` | 
|  | Mode      string                 `json:"mode"` | 
|  | Revision  string                 `json:"revision"` | 
|  | Groups    []mlkemKeyGenTestGroup `json:"testGroups"` | 
|  | } | 
|  |  | 
|  | type mlkemKeyGenTestGroup struct { | 
|  | ID           uint64            `json:"tgId"` | 
|  | TestType     string            `json:"testType"` | 
|  | ParameterSet string            `json:"parameterSet"` | 
|  | Tests        []mlkemKeyGenTest `json:"tests"` | 
|  | } | 
|  |  | 
|  | type mlkemKeyGenTest struct { | 
|  | ID uint64 `json:"tcId"` | 
|  | Z  string `json:"z"` | 
|  | D  string `json:"d"` | 
|  | } | 
|  |  | 
|  | type mlkemKeyGenTestGroupResponse struct { | 
|  | ID    uint64                    `json:"tgId"` | 
|  | Tests []mlkemKeyGenTestResponse `json:"tests"` | 
|  | } | 
|  |  | 
|  | type mlkemKeyGenTestResponse struct { | 
|  | ID uint64 `json:"tcId"` | 
|  | EK string `json:"ek"` | 
|  | DK string `json:"dk"` | 
|  | } | 
|  |  | 
|  | type mlkemEncapDecapTestVectorSet struct { | 
|  | Algorithm string                     `json:"algorithm"` | 
|  | Mode      string                     `json:"mode"` | 
|  | Revision  string                     `json:"revision"` | 
|  | Groups    []mlkemEncapDecapTestGroup `json:"testGroups"` | 
|  | } | 
|  |  | 
|  | type mlkemEncapDecapTestGroup struct { | 
|  | ID           uint64                `json:"tgId"` | 
|  | TestType     string                `json:"testType"` | 
|  | ParameterSet string                `json:"parameterSet"` | 
|  | Function     string                `json:"function"` | 
|  | DK           string                `json:"dk,omitempty"` | 
|  | Tests        []mlkemEncapDecapTest `json:"tests"` | 
|  | } | 
|  |  | 
|  | type mlkemEncapDecapTest struct { | 
|  | ID uint64 `json:"tcId"` | 
|  | EK string `json:"ek,omitempty"` | 
|  | M  string `json:"m,omitempty"` | 
|  | C  string `json:"c,omitempty"` | 
|  | } | 
|  |  | 
|  | type mlkemEncapDecapTestGroupResponse struct { | 
|  | ID    uint64                        `json:"tgId"` | 
|  | Tests []mlkemEncapDecapTestResponse `json:"tests"` | 
|  | } | 
|  |  | 
|  | type mlkemEncapDecapTestResponse struct { | 
|  | ID uint64 `json:"tcId"` | 
|  | C  string `json:"c,omitempty"` | 
|  | K  string `json:"k,omitempty"` | 
|  | } | 
|  |  | 
|  | type mlkem struct{} | 
|  |  | 
|  | func (m *mlkem) Process(vectorSet []byte, t Transactable) (any, error) { | 
|  | var common mlkemTestVectorSet | 
|  | if err := json.Unmarshal(vectorSet, &common); err != nil { | 
|  | return nil, fmt.Errorf("failed to unmarshal vector set: %v", err) | 
|  | } | 
|  |  | 
|  | switch common.Mode { | 
|  | case "keyGen": | 
|  | return m.processKeyGen(vectorSet, t) | 
|  | case "encapDecap": | 
|  | return m.processEncapDecap(vectorSet, t) | 
|  | default: | 
|  | return nil, fmt.Errorf("unsupported ML-KEM mode: %q", common.Mode) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (m *mlkem) processKeyGen(vectorSet []byte, t Transactable) (any, error) { | 
|  | var parsed mlkemKeyGenTestVectorSet | 
|  | if err := json.Unmarshal(vectorSet, &parsed); err != nil { | 
|  | return nil, fmt.Errorf("failed to unmarshal keyGen vector set: %v", err) | 
|  | } | 
|  |  | 
|  | var ret []mlkemKeyGenTestGroupResponse | 
|  |  | 
|  | for _, group := range parsed.Groups { | 
|  | response := mlkemKeyGenTestGroupResponse{ | 
|  | ID: group.ID, | 
|  | } | 
|  |  | 
|  | if !strings.HasPrefix(group.ParameterSet, "ML-KEM-") { | 
|  | return nil, fmt.Errorf("invalid parameter set: %s", group.ParameterSet) | 
|  | } | 
|  | cmdName := group.ParameterSet + "/keyGen" | 
|  |  | 
|  | for _, test := range group.Tests { | 
|  | // Concatenate d and z to form the seed | 
|  | dBytes, err := hex.DecodeString(test.D) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("failed to decode d in test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  | zBytes, err := hex.DecodeString(test.Z) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("failed to decode z in test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | seed := make([]byte, len(dBytes)+len(zBytes)) | 
|  | copy(seed, dBytes) | 
|  | copy(seed[len(dBytes):], zBytes) | 
|  |  | 
|  | result, err := t.Transact(cmdName, 2, seed) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("key generation failed for test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | response.Tests = append(response.Tests, mlkemKeyGenTestResponse{ | 
|  | ID: test.ID, | 
|  | EK: hex.EncodeToString(result[0]), | 
|  | DK: hex.EncodeToString(result[1]), | 
|  | }) | 
|  | } | 
|  |  | 
|  | ret = append(ret, response) | 
|  | } | 
|  |  | 
|  | return ret, nil | 
|  | } | 
|  |  | 
|  | func (m *mlkem) processEncapDecap(vectorSet []byte, t Transactable) (any, error) { | 
|  | var parsed mlkemEncapDecapTestVectorSet | 
|  | if err := json.Unmarshal(vectorSet, &parsed); err != nil { | 
|  | return nil, fmt.Errorf("failed to unmarshal encapDecap vector set: %v", err) | 
|  | } | 
|  |  | 
|  | var ret []mlkemEncapDecapTestGroupResponse | 
|  |  | 
|  | for _, group := range parsed.Groups { | 
|  | response := mlkemEncapDecapTestGroupResponse{ | 
|  | ID: group.ID, | 
|  | } | 
|  |  | 
|  | if !strings.HasPrefix(group.ParameterSet, "ML-KEM-") { | 
|  | return nil, fmt.Errorf("invalid parameter set: %s", group.ParameterSet) | 
|  | } | 
|  |  | 
|  | switch group.Function { | 
|  | case "encapsulation": | 
|  | cmdName := group.ParameterSet + "/encap" | 
|  | for _, test := range group.Tests { | 
|  | ek, err := hex.DecodeString(test.EK) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("failed to decode ek in test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | m, err := hex.DecodeString(test.M) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("failed to decode m in test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | result, err := t.Transact(cmdName, 2, ek, m) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("encapsulation failed for test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | response.Tests = append(response.Tests, mlkemEncapDecapTestResponse{ | 
|  | ID: test.ID, | 
|  | C:  hex.EncodeToString(result[0]), | 
|  | K:  hex.EncodeToString(result[1]), | 
|  | }) | 
|  | } | 
|  |  | 
|  | case "decapsulation": | 
|  | cmdName := group.ParameterSet + "/decap" | 
|  | dk, err := hex.DecodeString(group.DK) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("failed to decode dk in group %d: %s", | 
|  | group.ID, err) | 
|  | } | 
|  |  | 
|  | for _, test := range group.Tests { | 
|  | c, err := hex.DecodeString(test.C) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("failed to decode c in test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | result, err := t.Transact(cmdName, 1, dk, c) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("decapsulation failed for test case %d/%d: %s", | 
|  | group.ID, test.ID, err) | 
|  | } | 
|  |  | 
|  | response.Tests = append(response.Tests, mlkemEncapDecapTestResponse{ | 
|  | ID: test.ID, | 
|  | K:  hex.EncodeToString(result[0]), | 
|  | }) | 
|  | } | 
|  |  | 
|  | default: | 
|  | return nil, fmt.Errorf("unsupported function: %s", group.Function) | 
|  | } | 
|  |  | 
|  | ret = append(ret, response) | 
|  | } | 
|  |  | 
|  | return ret, nil | 
|  | } |