forked from aws/aws-lc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ACVP test harness for ML-DSA (aws#2127)
### Issues: Resolves #CryptoAlg-2819 ### Description of changes: Implements: - https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html - https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-keyGen-FIPS204 - https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigGen-FIPS204 - https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigVer-FIPS204 ### Additional Details Added testing for ML-DSA configured with`deterministic = true` `externalmu = true, false` `signatureInterface = internal` for `parameterSet = ML-DSA-44, ML-DSA-65, ML-DSA-87`. We add the [ML-DSA sigGen Test Case JSON Schema](https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html#name-ml-dsa-siggen-test-case-jso): ``` 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"` } } ``` and [ML-DSA sigVer Test Case JSON Schema](https://pages.nist.gov/ACVP/draft-celi-acvp-ml-dsa.html#name-ml-dsa-sigver-test-case-jso): ``` 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"` } } ``` ### Testing: ``` Running ACVP tests 2025/01/17 14:09:39 40 ACVP tests matched expectations 2025/01/17 14:09:40 1 ACVP tests matched expectations 2025/01/17 14:09:41 1 ACVP tests matched expectations 2025/01/17 14:09:42 1 ACVP tests matched expectations 2025/01/17 14:09:44 1 ACVP tests matched expectations 2025/01/17 14:09:46 1 ACVP tests matched expectations 2025/01/17 14:09:48 1 ACVP tests matched expectations 2025/01/17 14:09:50 1 ACVP tests matched expectations 2025/01/17 14:09:52 1 ACVP tests matched expectations 2025/01/17 14:10:09 1 ACVP tests matched expectations 2025/01/17 14:10:10 1 ACVP tests matched expectations 2025/01/17 14:10:11 1 ACVP tests matched expectations 2025/01/17 14:10:12 1 ACVP tests matched expectations 2025/01/17 14:10:12 1 ACVP tests matched expectations ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.
- Loading branch information
Showing
7 changed files
with
487 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Oops, something went wrong.