Skip to content

Commit 4da63d6

Browse files
authored
Merge pull request #498 from pq-code-package/acvp-prehash
Add support for HashML-DSA
2 parents f0961e7 + eff0c06 commit 4da63d6

File tree

18 files changed

+1360
-49
lines changed

18 files changed

+1360
-49
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,19 @@ By default, mldsa-native uses the "hedged" signing variant as specified in FIPS
8585

8686
The deterministic variant can be enabled by undefining `MLD_RANDOMIZED_SIGNING`, but FIPS 204 warns that this should not be used on platforms where fault injection attacks and side-channel attacks are a concern, as the lack of fresh randomness makes fault attacks more difficult to mitigate.
8787

88-
### Does mldsa-native support the pre-hash/digest sign/verify mode (external mu)?
88+
### Does mldsa-native support the external mu mode?
8989

9090
Yes. mldsa-native supports external mu mode, which allows for pre-hashing of messages before signing. This addresses the pre-hashing capability described in the NIST PQC FAQ[^NIST_FAQ] and detailed in NIST's guidance on FIPS 204 Section 6[^NIST_FIPS204_SEC6].
9191

9292
External mu mode enables applications to compute the message digest (mu) externally and provide it to the signing implementation, which is particularly useful for large messages or streaming applications where the entire message cannot be held in memory during signing.
9393

9494
### Does mldsa-native support HashML-DSA?
9595

96-
No. mldsa-native does not currently implement HashML-DSA, the hash-based variant of ML-DSA defined in FIPS 204. The current implementation focuses on the standard ML-DSA signature scheme.
96+
Yes. mldsa-native supports HashML-DSA, the pre-hashing variant of ML-DSA defined in FIPS 204 Algorithms 4 and 5.
97+
98+
mldsa-native provides two levels of API:
99+
- `crypto_sign_signature_pre_hash_internal` and `crypto_sign_verify_pre_hash_internal` - Low-level functions that accept a pre-hashed message digest. This function supports all 12 allowed hash functions.
100+
- `crypto_sign_signature_pre_hash_shake256` and `crypto_sign_verify_pre_hash_shake256` - High-level functions that perform SHAKE256 pre-hashing internally for convenience. Currently, only SHAKE256 is supported. If you require another hash function, use the `*_pre_hash_internal` functions or open an issue.
97101

98102
### Will I be able to bring my own backend?
99103

integration/liboqs/ML-DSA-44_META.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ implementations:
3131
sources: integration/liboqs/config_c.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h
3232
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
3333
mldsa/ntt.c mldsa/ntt.h mldsa/packing.c mldsa/packing.h mldsa/params.h mldsa/poly.c
34-
mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c mldsa/polyvec.h mldsa/randombytes.h
35-
mldsa/reduce.h mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h
36-
mldsa/zetas.inc
34+
mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h
35+
mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c mldsa/sign.h
36+
mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
3737
- name: x86_64
3838
version: FIPS204
3939
folder_name: .
@@ -46,8 +46,9 @@ implementations:
4646
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
4747
mldsa/native/api.h mldsa/native/meta.h mldsa/ntt.c mldsa/ntt.h mldsa/packing.c
4848
mldsa/packing.h mldsa/params.h mldsa/poly.c mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c
49-
mldsa/polyvec.h mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c
50-
mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc mldsa/native/x86_64
49+
mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h mldsa/randombytes.h mldsa/reduce.h
50+
mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
51+
mldsa/native/x86_64
5152
supported_platforms:
5253
- architecture: x86_64
5354
operating_systems:
@@ -69,8 +70,9 @@ implementations:
6970
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
7071
mldsa/native/api.h mldsa/native/meta.h mldsa/ntt.c mldsa/ntt.h mldsa/packing.c
7172
mldsa/packing.h mldsa/params.h mldsa/poly.c mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c
72-
mldsa/polyvec.h mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c
73-
mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc mldsa/native/aarch64
73+
mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h mldsa/randombytes.h mldsa/reduce.h
74+
mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
75+
mldsa/native/aarch64
7476
supported_platforms:
7577
- architecture: arm_8
7678
operating_systems:

integration/liboqs/ML-DSA-65_META.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ implementations:
3131
sources: integration/liboqs/config_c.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h
3232
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
3333
mldsa/ntt.c mldsa/ntt.h mldsa/packing.c mldsa/packing.h mldsa/params.h mldsa/poly.c
34-
mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c mldsa/polyvec.h mldsa/randombytes.h
35-
mldsa/reduce.h mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h
36-
mldsa/zetas.inc
34+
mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h
35+
mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c mldsa/sign.h
36+
mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
3737
- name: x86_64
3838
version: FIPS204
3939
folder_name: .
@@ -46,8 +46,9 @@ implementations:
4646
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
4747
mldsa/native/api.h mldsa/native/meta.h mldsa/ntt.c mldsa/ntt.h mldsa/packing.c
4848
mldsa/packing.h mldsa/params.h mldsa/poly.c mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c
49-
mldsa/polyvec.h mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c
50-
mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc mldsa/native/x86_64
49+
mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h mldsa/randombytes.h mldsa/reduce.h
50+
mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
51+
mldsa/native/x86_64
5152
supported_platforms:
5253
- architecture: x86_64
5354
operating_systems:
@@ -69,8 +70,9 @@ implementations:
6970
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
7071
mldsa/native/api.h mldsa/native/meta.h mldsa/ntt.c mldsa/ntt.h mldsa/packing.c
7172
mldsa/packing.h mldsa/params.h mldsa/poly.c mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c
72-
mldsa/polyvec.h mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c
73-
mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc mldsa/native/aarch64
73+
mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h mldsa/randombytes.h mldsa/reduce.h
74+
mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
75+
mldsa/native/aarch64
7476
supported_platforms:
7577
- architecture: arm_8
7678
operating_systems:

integration/liboqs/ML-DSA-87_META.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ implementations:
3131
sources: integration/liboqs/config_c.h integration/liboqs/fips202_glue.h integration/liboqs/fips202x4_glue.h
3232
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
3333
mldsa/ntt.c mldsa/ntt.h mldsa/packing.c mldsa/packing.h mldsa/params.h mldsa/poly.c
34-
mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c mldsa/polyvec.h mldsa/randombytes.h
35-
mldsa/reduce.h mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h
36-
mldsa/zetas.inc
34+
mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h
35+
mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c mldsa/sign.h
36+
mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
3737
- name: x86_64
3838
version: FIPS204
3939
folder_name: .
@@ -46,8 +46,9 @@ implementations:
4646
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
4747
mldsa/native/api.h mldsa/native/meta.h mldsa/ntt.c mldsa/ntt.h mldsa/packing.c
4848
mldsa/packing.h mldsa/params.h mldsa/poly.c mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c
49-
mldsa/polyvec.h mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c
50-
mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc mldsa/native/x86_64
49+
mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h mldsa/randombytes.h mldsa/reduce.h
50+
mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
51+
mldsa/native/x86_64
5152
supported_platforms:
5253
- architecture: x86_64
5354
operating_systems:
@@ -68,8 +69,9 @@ implementations:
6869
mldsa/cbmc.h mldsa/common.h mldsa/ct.c mldsa/ct.h mldsa/debug.c mldsa/debug.h
6970
mldsa/native/api.h mldsa/native/meta.h mldsa/ntt.c mldsa/ntt.h mldsa/packing.c
7071
mldsa/packing.h mldsa/params.h mldsa/poly.c mldsa/poly.h mldsa/poly_kl.c mldsa/polyvec.c
71-
mldsa/polyvec.h mldsa/randombytes.h mldsa/reduce.h mldsa/rounding.h mldsa/sign.c
72-
mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc mldsa/native/aarch64
72+
mldsa/polyvec.h mldsa/prehash.c mldsa/prehash.h mldsa/randombytes.h mldsa/reduce.h
73+
mldsa/rounding.h mldsa/sign.c mldsa/sign.h mldsa/symmetric.h mldsa/sys.h mldsa/zetas.inc
74+
mldsa/native/aarch64
7375
supported_platforms:
7476
- architecture: arm_8
7577
operating_systems:

mldsa/prehash.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright (c) The mldsa-native project authors
3+
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
4+
*/
5+
6+
#include "prehash.h"
7+
#include "symmetric.h"
8+
9+
#define MLD_PRE_HASH_OID_LEN 11
10+
11+
/*************************************************
12+
* Name: mld_get_hash_oid
13+
*
14+
* Description: Returns the OID of a given SHA-2/SHA-3 hash function.
15+
*
16+
* Arguments: - uint8_t oid[11]: pointer to output oid
17+
* - mld_hash_alg_t hashAlg: hash algorithm enumeration
18+
*
19+
**************************************************/
20+
static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN],
21+
mld_hash_alg_t hashAlg)
22+
{
23+
unsigned int i;
24+
static const struct
25+
{
26+
mld_hash_alg_t alg;
27+
uint8_t oid[MLD_PRE_HASH_OID_LEN];
28+
} oid_map[] = {
29+
{MLD_SHA2_224,
30+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}},
31+
{MLD_SHA2_256,
32+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}},
33+
{MLD_SHA2_384,
34+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}},
35+
{MLD_SHA2_512,
36+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}},
37+
{MLD_SHA2_512_224,
38+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05}},
39+
{MLD_SHA2_512_256,
40+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06}},
41+
{MLD_SHA3_224,
42+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07}},
43+
{MLD_SHA3_256,
44+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08}},
45+
{MLD_SHA3_384,
46+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}},
47+
{MLD_SHA3_512,
48+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A}},
49+
{MLD_SHAKE_128,
50+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B}},
51+
{MLD_SHAKE_256,
52+
{0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C}}};
53+
54+
for (i = 0; i < sizeof(oid_map) / sizeof(oid_map[0]); i++)
55+
__loop__(
56+
invariant(i <= sizeof(oid_map) / sizeof(oid_map[0]))
57+
)
58+
{
59+
if (oid_map[i].alg == hashAlg)
60+
{
61+
mld_memcpy(oid, oid_map[i].oid, MLD_PRE_HASH_OID_LEN);
62+
return;
63+
}
64+
}
65+
}
66+
67+
int mld_validate_hash_length(mld_hash_alg_t hashAlg, size_t len)
68+
{
69+
switch (hashAlg)
70+
{
71+
case MLD_SHA2_224:
72+
return (len == 224 / 8) ? 0 : -1;
73+
case MLD_SHA2_256:
74+
return (len == 256 / 8) ? 0 : -1;
75+
case MLD_SHA2_384:
76+
return (len == 384 / 8) ? 0 : -1;
77+
case MLD_SHA2_512:
78+
return (len == 512 / 8) ? 0 : -1;
79+
case MLD_SHA2_512_224:
80+
return (len == 224 / 8) ? 0 : -1;
81+
case MLD_SHA2_512_256:
82+
return (len == 256 / 8) ? 0 : -1;
83+
case MLD_SHA3_224:
84+
return (len == 224 / 8) ? 0 : -1;
85+
case MLD_SHA3_256:
86+
return (len == 256 / 8) ? 0 : -1;
87+
case MLD_SHA3_384:
88+
return (len == 384 / 8) ? 0 : -1;
89+
case MLD_SHA3_512:
90+
return (len == 512 / 8) ? 0 : -1;
91+
case MLD_SHAKE_128:
92+
return (len == 256 / 8) ? 0 : -1;
93+
case MLD_SHAKE_256:
94+
return (len == 512 / 8) ? 0 : -1;
95+
}
96+
return -1;
97+
}
98+
99+
size_t mld_format_pre_hash_message(
100+
uint8_t fmsg[MLD_PRE_HASH_MAX_FORMATTED_MESSAGE_BYTES], const uint8_t *ph,
101+
size_t phlen, const uint8_t *ctx, size_t ctxlen, mld_hash_alg_t hashAlg)
102+
{
103+
/* Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph */
104+
fmsg[0] = 1;
105+
fmsg[1] = (uint8_t)ctxlen;
106+
107+
/* Copy context if present */
108+
if (ctxlen > 0)
109+
{
110+
mld_memcpy(fmsg + 2, ctx, ctxlen);
111+
}
112+
113+
/* Write OID */
114+
mld_get_hash_oid(fmsg + 2 + ctxlen, hashAlg);
115+
116+
/* Copy pre-hash */
117+
mld_memcpy(fmsg + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen);
118+
119+
/* Return total formatted message length */
120+
return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen;
121+
}

mldsa/prehash.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) The mldsa-native project authors
3+
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
4+
*/
5+
6+
#ifndef MLD_PREHASH_H
7+
#define MLD_PREHASH_H
8+
9+
#include <stddef.h>
10+
#include <stdint.h>
11+
#include "common.h"
12+
#include "sign.h"
13+
14+
/* Maximum formatted pre-hash message length: 0x01 || ctxlen || ctx (max 255) ||
15+
* oid (11) || ph (max 64) */
16+
#define MLD_PRE_HASH_MAX_FORMATTED_MESSAGE_BYTES (2 + 255 + 11 + 64)
17+
18+
#define mld_validate_hash_length MLD_NAMESPACE(validate_hash_length)
19+
/*************************************************
20+
* Name: mld_validate_hash_length
21+
*
22+
* Description: Validates that the given hash length matches the expected
23+
* length for the given hash algorithm.
24+
*
25+
* Arguments: - mld_hash_alg_t hashAlg: hash algorithm enumeration
26+
* - size_t len: Hash length to be checked
27+
*
28+
* Returns 0 if hash algorithm is known and the hash length matches
29+
* and -1 otherwise.
30+
**************************************************/
31+
MLD_MUST_CHECK_RETURN_VALUE
32+
MLD_INTERNAL_API
33+
int mld_validate_hash_length(mld_hash_alg_t hashAlg, size_t len);
34+
35+
#define mld_format_pre_hash_message MLD_NAMESPACE(format_pre_hash_message)
36+
/*************************************************
37+
* Name: mld_format_pre_hash_message
38+
*
39+
* Description: Formats a pre-hash message according to FIPS 204:
40+
* 0x01 || ctxlen (1 byte) || ctx || oid || ph
41+
*
42+
* Arguments: - uint8_t fmsg[MLD_PRE_HASH_MAX_FORMATTED_MESSAGE_BYTES]:
43+
* output formatted message buffer
44+
* - const uint8_t *ph: pointer to pre-hashed message
45+
* - size_t phlen: length of pre-hashed message
46+
* - const uint8_t *ctx: pointer to context string (may be NULL)
47+
* - size_t ctxlen: length of context string
48+
* - mld_hash_alg_t hashAlg: hash algorithm enumeration
49+
*
50+
* Returns the total length of the formatted message (2 + ctxlen + 11 + phlen).
51+
**************************************************/
52+
MLD_INTERNAL_API
53+
size_t mld_format_pre_hash_message(
54+
uint8_t fmsg[MLD_PRE_HASH_MAX_FORMATTED_MESSAGE_BYTES], const uint8_t *ph,
55+
size_t phlen, const uint8_t *ctx, size_t ctxlen, mld_hash_alg_t hashAlg);
56+
57+
#endif /* !MLD_PREHASH_H */

0 commit comments

Comments
 (0)