Skip to content

Commit 1276fc7

Browse files
[Cherry-pick FIPS 2025] Route ML-DSA ACVP to the right APIs (#2890)
cherry picked from commit on main: 745d009 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.
1 parent 56ebad6 commit 1276fc7

File tree

4 files changed

+39
-26
lines changed

4 files changed

+39
-26
lines changed

util/fipstools/acvp/acvptool/subprocess/ml_dsa.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ type mlDsaSigGenTestGroup struct {
100100
ParameterSet string `json:"parameterSet"`
101101
Deterministic bool `json:"deterministic"`
102102
SignatureInterface string `json:"signatureInterface"`
103-
ExternalMu bool `json:"externalMu`
103+
ExternalMu *bool `json:"externalMu`
104104
Tests []struct {
105105
ID uint64 `json:"tcId"`
106106
Message hexEncodedByteString `json:"message"`
@@ -123,8 +123,11 @@ type mlDsaSigGenTestCaseResponse struct {
123123
}
124124

125125
// Convert boolean to byte slice (using 1 for true, 0 for false)
126-
func boolToBytes(b bool) []byte {
127-
if b {
126+
func boolToBytes(b *bool) []byte {
127+
if b == nil {
128+
return nil // Field doesn't exist
129+
}
130+
if *b {
128131
return []byte{1}
129132
}
130133
return []byte{0}
@@ -174,7 +177,7 @@ type mlDsaSigVerTestGroup struct {
174177
ParameterSet string `json:"parameterSet"`
175178
Deterministic bool `json:"deterministic"`
176179
SignatureInterface string `json:"signatureInterface"`
177-
ExternalMu bool `json:"externalMu`
180+
ExternalMu *bool `json:"externalMu`
178181
Tests []struct {
179182
ID uint64 `json:"tcId"`
180183
PK hexEncodedByteString `json:"pk"`
959 KB
Binary file not shown.
1.31 MB
Binary file not shown.

util/fipstools/acvp/modulewrapper/modulewrapper.cc

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3322,31 +3322,29 @@ static bool ML_DSA_SIGGEN(const Span<const uint8_t> args[],
33223322
const Span<const uint8_t> context = args[4];
33233323
const Span<const uint8_t> extmu = args[5];
33243324

3325-
using SignFunc = int (*)(const uint8_t*, uint8_t*, size_t*,
3326-
const uint8_t*, size_t, const uint8_t*, size_t);
33273325
using SignInternalFunc = int (*)(const uint8_t*, uint8_t*, size_t*,
33283326
const uint8_t*, size_t,
33293327
const uint8_t*, size_t, const uint8_t*);
33303328

33313329
// Group all related functions for each variant
33323330
struct MLDSA_functions {
33333331
void (*params_init)(ml_dsa_params*);
3334-
SignFunc sign;
33353332
SignInternalFunc sign_internal;
33363333
SignInternalFunc extmu_sign_internal;
33373334
};
33383335

3339-
// Select function set based on NID
3336+
// Select function set based on NID. We must use |ml_dsa_*_sign_internal| here,
3337+
// to account for the random inputs (rnd).
33403338
MLDSA_functions mldsa_funcs;
33413339
if (nid == NID_MLDSA44) {
3342-
mldsa_funcs = {ml_dsa_44_params_init, ml_dsa_44_sign,
3343-
ml_dsa_44_sign_internal, ml_dsa_extmu_44_sign_internal};
3340+
mldsa_funcs = {ml_dsa_44_params_init, ml_dsa_44_sign_internal,
3341+
ml_dsa_extmu_44_sign_internal};
33443342
} else if (nid == NID_MLDSA65) {
3345-
mldsa_funcs = {ml_dsa_65_params_init, ml_dsa_65_sign,
3346-
ml_dsa_65_sign_internal, ml_dsa_extmu_65_sign_internal};
3343+
mldsa_funcs = {ml_dsa_65_params_init, ml_dsa_65_sign_internal,
3344+
ml_dsa_extmu_65_sign_internal};
33473345
} else if (nid == NID_MLDSA87) {
3348-
mldsa_funcs = {ml_dsa_87_params_init, ml_dsa_87_sign,
3349-
ml_dsa_87_sign_internal, ml_dsa_extmu_87_sign_internal};
3346+
mldsa_funcs = {ml_dsa_87_params_init, ml_dsa_87_sign_internal,
3347+
ml_dsa_extmu_87_sign_internal};
33503348
} else {
33513349
return false;
33523350
}
@@ -3357,12 +3355,8 @@ static bool ML_DSA_SIGGEN(const Span<const uint8_t> args[],
33573355
size_t signature_len = params.bytes;
33583356
std::vector<uint8_t> signature(signature_len);
33593357

3360-
if (!context.empty()) {
3361-
if (!mldsa_funcs.sign(sk.data(), signature.data(), &signature_len,
3362-
msg.data(), msg.size(), context.data(), context.size())) {
3363-
return false;
3364-
}
3365-
} else {
3358+
if (!extmu.empty()) {
3359+
// Only signatureInterface: internal contains the externalMu field.
33663360
if (extmu.data()[0] == 0) {
33673361
// generate the signatures raw sign mode
33683362
if (!mldsa_funcs.sign_internal(sk.data(), signature.data(), &signature_len,
@@ -3376,6 +3370,20 @@ static bool ML_DSA_SIGGEN(const Span<const uint8_t> args[],
33763370
return false;
33773371
}
33783372
}
3373+
} else {
3374+
// |context| is unique to signatureInterface: external.
3375+
//
3376+
// Prepare |pre| exactly how |ml_dsa_sign| is doing. The maximum |context| size
3377+
// for ML-DSA is 255 bytes. We append a 0 and the size as two additional bytes
3378+
// before |context| to become the prefix string.
3379+
uint8_t pre[257];
3380+
pre[0] = 0;
3381+
pre[1] = context.size();
3382+
OPENSSL_memcpy(pre + 2 , context.data(), context.size());
3383+
if (!mldsa_funcs.sign_internal(sk.data(), signature.data(), &signature_len,
3384+
msg.data(), msg.size(), pre, 2 + context.size(), rnd.data())) {
3385+
return false;
3386+
}
33793387
}
33803388

33813389
return write_reply({Span<const uint8_t>(signature)});
@@ -3418,12 +3426,8 @@ static bool ML_DSA_SIGVER(const Span<const uint8_t> args[], ReplyCallback write_
34183426
}
34193427

34203428
uint8_t reply[1] = {0};
3421-
if (!context.empty()) {
3422-
if (mldsa_funcs.verify(pk.data(), sig.data(), sig.size(), msg.data(),
3423-
msg.size(), context.data(), context.size())) {
3424-
reply[0] = 1;
3425-
}
3426-
} else {
3429+
if (!extmu.empty()) {
3430+
// Only signatureInterface: internal contains the externalMu field.
34273431
if (extmu.data()[0] == 0) {
34283432
// verify the signatures raw sign mode
34293433
if (mldsa_funcs.verify_internal(pk.data(), sig.data(), sig.size(), msg.data(),
@@ -3437,6 +3441,12 @@ static bool ML_DSA_SIGVER(const Span<const uint8_t> args[], ReplyCallback write_
34373441
reply[0] = 1;
34383442
}
34393443
}
3444+
} else {
3445+
// |context| is unique to signatureInterface: external.
3446+
if (mldsa_funcs.verify(pk.data(), sig.data(), sig.size(), msg.data(),
3447+
msg.size(), context.data(), context.size())) {
3448+
reply[0] = 1;
3449+
}
34403450
}
34413451

34423452
return write_reply({Span<const uint8_t>(reply)});

0 commit comments

Comments
 (0)