Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACVP test harness for ML-DSA #2127

Merged
merged 7 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions crypto/ml_dsa/ml_dsa_ref/params.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#ifndef ML_DSA_PARAMS_H
#define ML_DSA_PARAMS_H

#if defined(__cplusplus)
extern "C" {
#endif

// The only defined parameters are those that don't depend
// on the parameter set. All other parameters are specified
// in ml_dsa_params structure that is unique for each parameter
Expand Down Expand Up @@ -44,8 +48,11 @@ typedef struct {
#define ML_DSA_POLY_UNIFORM_ETA_NBLOCKS_MAX ((227 + SHAKE256_BLOCKSIZE - 1)/SHAKE256_BLOCKSIZE)
#define ML_DSA_POLYZ_PACKEDBYTES_MAX (576)

void ml_dsa_44_params_init(ml_dsa_params *params);
void ml_dsa_65_params_init(ml_dsa_params *params);
void ml_dsa_87_params_init(ml_dsa_params *params);
OPENSSL_EXPORT void ml_dsa_44_params_init(ml_dsa_params *params);
OPENSSL_EXPORT void ml_dsa_65_params_init(ml_dsa_params *params);
OPENSSL_EXPORT void ml_dsa_87_params_init(ml_dsa_params *params);

#if defined(__cplusplus)
}
#endif
#endif
239 changes: 239 additions & 0 deletions util/fipstools/acvp/acvptool/subprocess/ml_dsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
// 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"
)

type mlDsa struct{}

func (*mlDsa) 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
}

switch {
case strings.EqualFold(vs.Mode, "keyGen"):
return processMlDsaKeyGen(vs.TestGroups, m)
case strings.EqualFold(vs.Mode, "sigGen"):
return processMlDsaSigGen(vs.TestGroups, m)
case strings.EqualFold(vs.Mode, "sigVer"):
return processMlDsaSigVer(vs.TestGroups, m)
}

return nil, fmt.Errorf("unknown ML-DSA mode: %v", vs.Mode)
}

type mlDsaKeyGenTestGroup struct {
ID uint64 `json:"tgId"`
Type string `json:"testType"`
ParameterSet string `json:"parameterSet"`
Tests []struct {
ID uint64 `json:"tcId"`
SEED hexEncodedByteString `json:"seed"`
}
}

type mlDsaKeyGenTestGroupResponse struct {
ID uint64 `json:"tgId"`
Tests []mlDsaKeyGenTestCaseResponse `json:"tests"`
}

type mlDsaKeyGenTestCaseResponse struct {
ID uint64 `json:"tcId"`
PK hexEncodedByteString `json:"pk"`
SK hexEncodedByteString `json:"sk"`
}

func processMlDsaKeyGen(vectors json.RawMessage, m Transactable) (interface{}, error) {
var groups []mlDsaKeyGenTestGroup

if err := json.Unmarshal(vectors, &groups); err != nil {
return nil, err
}

var responses []mlDsaKeyGenTestGroupResponse

for _, group := range groups {
if !strings.EqualFold(group.Type, "AFT") {
return nil, fmt.Errorf("unsupported keyGen test type: %v", group.Type)
}

response := mlDsaKeyGenTestGroupResponse{
ID: group.ID,
}

for _, test := range group.Tests {
results, err := m.Transact("ML-DSA/"+group.ParameterSet+"/keyGen", 2, test.SEED)
if err != nil {
return nil, err
}

pk := results[0]
sk := results[1]

response.Tests = append(response.Tests, mlDsaKeyGenTestCaseResponse{
ID: test.ID,
PK: pk,
SK: sk,
})
}

responses = append(responses, response)
}

return responses, nil
}

type mlDsaSigGenTestGroup struct {
ID uint64 `json:"tgId"`
Type string `json:"testType"`
ParameterSet string `json:"parameterSet"`
Deterministic bool `json:"deterministic"`
SignatureInterface string `json:"signatureInterface"`
ExternalMu bool `json:"externalMu`
Tests []struct {
ID uint64 `json:"tcId"`
Message hexEncodedByteString `json:"message"`
MU hexEncodedByteString `json:"mu"`
SK hexEncodedByteString `json:"sk"`
RND hexEncodedByteString `json:"rnd"`
Context hexEncodedByteString `json:"context"`
HashAlg string `json:"hashAlg"`
}
}

type mlDsaSigGenTestGroupResponse struct {
ID uint64 `json:"tgId"`
Tests []mlDsaSigGenTestCaseResponse `json:"tests"`
}

type mlDsaSigGenTestCaseResponse struct {
ID uint64 `json:"tcId"`
Signature hexEncodedByteString `json:"signature"`
}

// Convert boolean to byte slice (using 1 for true, 0 for false)
func boolToBytes(b bool) []byte {
if b {
return []byte{1}
}
return []byte{0}
}

func processMlDsaSigGen(vectors json.RawMessage, m Transactable) (interface{}, error) {
var groups []mlDsaSigGenTestGroup

if err := json.Unmarshal(vectors, &groups); err != nil {
return nil, err
}

var responses []mlDsaSigGenTestGroupResponse

for _, group := range groups {
if !strings.EqualFold(group.Type, "AFT") {
return nil, fmt.Errorf("unsupported sigGen test type: %v", group.Type)
}

response := mlDsaSigGenTestGroupResponse{
ID: group.ID,
}

for _, test := range group.Tests {
results, err := m.Transact("ML-DSA/"+group.ParameterSet+"/sigGen",
1, test.SK, test.Message, test.MU, test.RND, boolToBytes(group.ExternalMu))
if err != nil {
return nil, err
}

signature := results[0]

response.Tests = append(response.Tests, mlDsaSigGenTestCaseResponse{
ID: test.ID,
Signature: signature,
})
}

responses = append(responses, response)
}
return responses, nil
}

type mlDsaSigVerTestGroup struct {
ID uint64 `json:"tgId"`
Type string `json:"testType"`
ParameterSet string `json:"parameterSet"`
Deterministic bool `json:"deterministic"`
SignatureInterface string `json:"signatureInterface"`
ExternalMu bool `json:"externalMu`
Tests []struct {
ID uint64 `json:"tcId"`
PK hexEncodedByteString `json:"pk"`
Message hexEncodedByteString `json:"message"`
MU hexEncodedByteString `json:"mu"`
Signature hexEncodedByteString `json:"signature"`
Context hexEncodedByteString `json:"context"`
HashAlg string `json:"hashAlg"`
}
}

type mlDsaSigVerTestGroupResponse struct {
ID uint64 `json:"tgId"`
Tests []mlDsaSigVerTestCaseResponse `json:"tests"`
}

type mlDsaSigVerTestCaseResponse struct {
ID uint64 `json:"tcId"`
TestPassed *bool `json:"testPassed"`
}

func processMlDsaSigVer(vectors json.RawMessage, m Transactable) (interface{}, error) {
var groups []mlDsaSigVerTestGroup

if err := json.Unmarshal(vectors, &groups); err != nil {
return nil, err
}

var responses []mlDsaSigVerTestGroupResponse

for _, group := range groups {
if !strings.EqualFold(group.Type, "AFT") {
return nil, fmt.Errorf("unsupported sigVer test type: %v", group.Type)
}

response := mlDsaSigVerTestGroupResponse{
ID: group.ID,
}

for _, test := range group.Tests {
results, err := m.Transact("ML-DSA/"+group.ParameterSet+"/sigVer", 1,
test.Signature, test.PK, test.Message, test.MU, boolToBytes(group.ExternalMu))
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, mlDsaSigVerTestCaseResponse{
ID: test.ID,
TestPassed: passed,
})
}

responses = append(responses, response)
}
return responses, nil
}
1 change: 1 addition & 0 deletions util/fipstools/acvp/acvptool/subprocess/subprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess
"PBKDF": &pbkdf{},
"ML-KEM": &mlKem{},
"EDDSA": &eddsa{},
"ML-DSA": &mlDsa{},
}
m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives}

Expand Down
Binary file not shown.
3 changes: 2 additions & 1 deletion util/fipstools/acvp/acvptool/test/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@
{"Wrapper": "modulewrapper", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/EDDSA-KeyGen.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/EDDSA-SigGen.bz2"}
{"Wrapper": "modulewrapper", "In": "vectors/EDDSA-SigGen.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/ML-DSA.bz2", "Out": "expected/ML-DSA.bz2"}
]
Binary file not shown.
Loading
Loading