Skip to content

Commit 7fb0e3d

Browse files
committed
Add support for PreHash ML-DSA
This commit adds two functions crypto_sign_signature_pre_hash_internal and crypto_sign_verify_pre_hash_internal implementing the pre-hashing mode of ML-DSA. Instead of receiving a message, they receive a pre-hashed message. Details can be found in Algorithm 4 and 5 in FIPS204. The message to signed is formatted as 0x01 || ctxlen (1 byte) || ctx || oid || ph where ph is the pre-hash and oid is the object identifier of the used hash algorithm. The ACVP client is adjusted to support the pre-hashing test cases. Note that the ACVP testvectors only contain the message, not the pre-hash. I opted for computing the hash in the ACVP Python client as for that we do not have to add implementations for the 12 hash functions. CBMC proofs for the new functions are added. Resolves #39 Signed-off-by: Matthias J. Kannwischer <[email protected]>
1 parent 4e99a8e commit 7fb0e3d

File tree

13 files changed

+891
-35
lines changed

13 files changed

+891
-35
lines changed

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 */

mldsa/sign.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "packing.h"
3232
#include "poly.h"
3333
#include "polyvec.h"
34+
#include "prehash.h"
3435
#include "randombytes.h"
3536
#include "sign.h"
3637
#include "symmetric.h"
@@ -862,3 +863,69 @@ int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen,
862863

863864
return -1;
864865
}
866+
867+
868+
MLD_MUST_CHECK_RETURN_VALUE
869+
MLD_EXTERNAL_API
870+
int crypto_sign_signature_pre_hash_internal(uint8_t *sig, size_t *siglen,
871+
const uint8_t *ph, size_t phlen,
872+
const uint8_t *ctx, size_t ctxlen,
873+
const uint8_t rnd[MLDSA_RNDBYTES],
874+
const uint8_t *sk,
875+
mld_hash_alg_t hashAlg)
876+
{
877+
MLD_ALIGN uint8_t fmsg[MLD_PRE_HASH_MAX_FORMATTED_MESSAGE_BYTES];
878+
size_t fmsg_len;
879+
int result;
880+
881+
if (ctxlen > 255)
882+
{
883+
*siglen = 0;
884+
return -1;
885+
}
886+
887+
if (mld_validate_hash_length(hashAlg, phlen))
888+
{
889+
*siglen = 0;
890+
return -1;
891+
}
892+
893+
fmsg_len = mld_format_pre_hash_message(fmsg, ph, phlen, ctx, ctxlen, hashAlg);
894+
895+
result = crypto_sign_signature_internal(sig, siglen, fmsg, fmsg_len, NULL, 0,
896+
rnd, sk, 0);
897+
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
898+
mld_zeroize(fmsg, sizeof(fmsg));
899+
return result;
900+
}
901+
902+
MLD_MUST_CHECK_RETURN_VALUE
903+
MLD_EXTERNAL_API
904+
int crypto_sign_verify_pre_hash_internal(const uint8_t *sig, size_t siglen,
905+
const uint8_t *ph, size_t phlen,
906+
const uint8_t *ctx, size_t ctxlen,
907+
const uint8_t *pk,
908+
mld_hash_alg_t hashAlg)
909+
{
910+
MLD_ALIGN uint8_t fmsg[MLD_PRE_HASH_MAX_FORMATTED_MESSAGE_BYTES];
911+
size_t fmsg_len;
912+
int result;
913+
914+
if (ctxlen > 255)
915+
{
916+
return -1;
917+
}
918+
919+
if (mld_validate_hash_length(hashAlg, phlen))
920+
{
921+
return -1;
922+
}
923+
924+
fmsg_len = mld_format_pre_hash_message(fmsg, ph, phlen, ctx, ctxlen, hashAlg);
925+
926+
result =
927+
crypto_sign_verify_internal(sig, siglen, fmsg, fmsg_len, NULL, 0, pk, 0);
928+
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
929+
mld_zeroize(fmsg, sizeof(fmsg));
930+
return result;
931+
}

0 commit comments

Comments
 (0)