diff --git a/Makefile.Microsoft_nmake b/Makefile.Microsoft_nmake index ea998f0b7..a02dad782 100644 --- a/Makefile.Microsoft_nmake +++ b/Makefile.Microsoft_nmake @@ -5,7 +5,8 @@ CFLAGS = /nologo /O2 /Imldsa /Imlmdsa/fips202 /Imldsa/fips202/native /Imldsa/native OBJ_FILES = .\mldsa\*.obj \ - .\mldsa\fips202\*.obj + .\mldsa\fips202\*.obj \ + .\mldsa\sha2\*.obj BUILD_DIR = test\build MLDSA44_BUILD_DIR = $(BUILD_DIR)\mldsa44 @@ -13,11 +14,14 @@ MLDSA65_BUILD_DIR = $(BUILD_DIR)\mldsa65 MLDSA87_BUILD_DIR = $(BUILD_DIR)\mldsa87 OBJ_FILES_44 = $(MLDSA44_BUILD_DIR)\mldsa\*.obj \ - $(MLDSA44_BUILD_DIR)\mldsa\fips202\*.obj + $(MLDSA44_BUILD_DIR)\mldsa\fips202\*.obj \ + $(MLDSA44_BUILD_DIR)\mldsa\sha2\*.obj OBJ_FILES_65 = $(MLDSA65_BUILD_DIR)\mldsa\*.obj \ - $(MLDSA65_BUILD_DIR)\mldsa\fips202\*.obj + $(MLDSA65_BUILD_DIR)\mldsa\fips202\*.obj \ + $(MLDSA65_BUILD_DIR)\mldsa\sha2\*.obj OBJ_FILES_87 = $(MLDSA87_BUILD_DIR)\mldsa\*.obj \ - $(MLDSA87_BUILD_DIR)\mldsa\fips202\*.obj + $(MLDSA87_BUILD_DIR)\mldsa\fips202\*.obj \ + $(MLDSA87_BUILD_DIR)\mldsa\sha2\*.obj # NOTE: We currently only build code for non-opt code, as we haven't yet made the assembly compatible on Windows !IFNDEF OPT @@ -37,6 +41,10 @@ OPT = 0 @if NOT EXIST $(MLDSA44_BUILD_DIR)\mldsa\fips202 mkdir $(MLDSA44_BUILD_DIR)\mldsa\fips202 $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /c /Fo$(MLDSA44_BUILD_DIR)\mldsa\fips202\ $< +{mldsa\sha2}.c{$(MLDSA44_BUILD_DIR)\mldsa\sha2}.obj:: + @if NOT EXIST $(MLDSA44_BUILD_DIR)\mldsa\sha2 mkdir $(MLDSA44_BUILD_DIR)\mldsa\sha2 + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /c /Fo$(MLDSA44_BUILD_DIR)\mldsa\sha2\ $< + {test}.c{$(MLDSA44_BUILD_DIR)\test}.obj:: @if NOT EXIST $(MLDSA44_BUILD_DIR)\test mkdir $(MLDSA44_BUILD_DIR)\test $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=44 /c /Fo$(MLDSA44_BUILD_DIR)\test\ $< @@ -50,6 +58,10 @@ OPT = 0 @if NOT EXIST $(MLDSA65_BUILD_DIR)\mldsa\fips202 mkdir $(MLDSA65_BUILD_DIR)\mldsa\fips202 $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /c /Fo$(MLDSA65_BUILD_DIR)\mldsa\fips202\ $< +{mldsa\sha2}.c{$(MLDSA65_BUILD_DIR)\mldsa\sha2}.obj:: + @if NOT EXIST $(MLDSA65_BUILD_DIR)\mldsa\sha2 mkdir $(MLDSA65_BUILD_DIR)\mldsa\sha2 + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /c /Fo$(MLDSA65_BUILD_DIR)\mldsa\sha2\ $< + {test}.c{$(MLDSA65_BUILD_DIR)\test}.obj:: @if NOT EXIST $(MLDSA65_BUILD_DIR)\test mkdir $(MLDSA65_BUILD_DIR)\test $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=65 /c /Fo$(MLDSA65_BUILD_DIR)\test\ $< @@ -63,6 +75,10 @@ OPT = 0 @if NOT EXIST $(MLDSA87_BUILD_DIR)\mldsa\fips202 mkdir $(MLDSA87_BUILD_DIR)\mldsa\fips202 $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /c /Fo$(MLDSA87_BUILD_DIR)\mldsa\fips202\ $< +{mldsa\sha2}.c{$(MLDSA87_BUILD_DIR)\mldsa\sha2}.obj:: + @if NOT EXIST $(MLDSA87_BUILD_DIR)\mldsa\sha2 mkdir $(MLDSA87_BUILD_DIR)\mldsa\sha2 + $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /c /Fo$(MLDSA87_BUILD_DIR)\mldsa\sha2\ $< + {test}.c{$(MLDSA87_BUILD_DIR)\test}.obj:: @if NOT EXIST $(MLDSA87_BUILD_DIR)\test mkdir $(MLDSA87_BUILD_DIR)\test $(CC) $(CFLAGS) /D MLD_CONFIG_PARAMETER_SET=87 /c /Fo$(MLDSA87_BUILD_DIR)\test\ $< diff --git a/mldsa/fips202/fips202.c b/mldsa/fips202/fips202.c index 970dcf2e4..c2feb2d6a 100644 --- a/mldsa/fips202/fips202.c +++ b/mldsa/fips202/fips202.c @@ -145,6 +145,9 @@ static unsigned int keccak_squeeze(uint8_t *out, size_t outlen, __contract__( requires((r == SHAKE128_RATE && pos <= SHAKE128_RATE) || (r == SHAKE256_RATE && pos <= SHAKE256_RATE) || + (r == SHA3_224_RATE && pos <= SHA3_224_RATE) || + (r == SHA3_256_RATE && pos <= SHA3_256_RATE) || + (r == SHA3_384_RATE && pos <= SHA3_384_RATE) || (r == SHA3_512_RATE && pos <= SHA3_512_RATE)) requires(outlen <= 8 * r /* somewhat arbitrary bound */) requires(memory_no_alias(s, sizeof(uint64_t) * MLD_KECCAK_LANES)) @@ -245,6 +248,17 @@ void mld_shake256_release(mld_shake256ctx *state) mld_zeroize(state, sizeof(mld_shake256ctx)); } +void mld_shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +{ + mld_shake128ctx state; + + mld_shake128_init(&state); + mld_shake128_absorb(&state, in, inlen); + mld_shake128_finalize(&state); + mld_shake128_squeeze(out, outlen, &state); + mld_shake128_release(&state); +} + void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { mld_shake256ctx state; @@ -255,3 +269,47 @@ void mld_shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) mld_shake256_squeeze(out, outlen, &state); mld_shake256_release(&state); } + +void mld_sha3_256(uint8_t *out, const uint8_t *in, size_t inlen) +{ + uint64_t s[MLD_KECCAK_LANES]; + + keccak_init(s); + keccak_absorb(s, 0, SHA3_256_RATE, in, inlen); + keccak_finalize(s, inlen % SHA3_256_RATE, SHA3_256_RATE, 0x06); + keccak_squeeze(out, SHA3_256_HASHBYTES, s, SHA3_256_RATE, SHA3_256_RATE); + mld_zeroize(s, sizeof(s)); +} + +void mld_sha3_384(uint8_t *out, const uint8_t *in, size_t inlen) +{ + uint64_t s[MLD_KECCAK_LANES]; + + keccak_init(s); + keccak_absorb(s, 0, SHA3_384_RATE, in, inlen); + keccak_finalize(s, inlen % SHA3_384_RATE, SHA3_384_RATE, 0x06); + keccak_squeeze(out, SHA3_384_HASHBYTES, s, SHA3_384_RATE, SHA3_384_RATE); + mld_zeroize(s, sizeof(s)); +} + +void mld_sha3_224(uint8_t *out, const uint8_t *in, size_t inlen) +{ + uint64_t s[MLD_KECCAK_LANES]; + + keccak_init(s); + keccak_absorb(s, 0, SHA3_224_RATE, in, inlen); + keccak_finalize(s, inlen % SHA3_224_RATE, SHA3_224_RATE, 0x06); + keccak_squeeze(out, SHA3_224_HASHBYTES, s, SHA3_224_RATE, SHA3_224_RATE); + mld_zeroize(s, sizeof(s)); +} + +void mld_sha3_512(uint8_t *out, const uint8_t *in, size_t inlen) +{ + uint64_t s[MLD_KECCAK_LANES]; + + keccak_init(s); + keccak_absorb(s, 0, SHA3_512_RATE, in, inlen); + keccak_finalize(s, inlen % SHA3_512_RATE, SHA3_512_RATE, 0x06); + keccak_squeeze(out, SHA3_512_HASHBYTES, s, SHA3_512_RATE, SHA3_512_RATE); + mld_zeroize(s, sizeof(s)); +} diff --git a/mldsa/fips202/fips202.h b/mldsa/fips202/fips202.h index 3abbc7626..2b35f9c9e 100644 --- a/mldsa/fips202/fips202.h +++ b/mldsa/fips202/fips202.h @@ -11,10 +11,14 @@ #define SHAKE128_RATE 168 #define SHAKE256_RATE 136 +#define SHA3_224_RATE 144 #define SHA3_256_RATE 136 +#define SHA3_384_RATE 104 #define SHA3_512_RATE 72 #define MLD_KECCAK_LANES 25 +#define SHA3_224_HASHBYTES 28 #define SHA3_256_HASHBYTES 32 +#define SHA3_384_HASHBYTES 48 #define SHA3_512_HASHBYTES 64 #define FIPS202_NAMESPACE(s) mldsa_fips202_ref_##s @@ -121,6 +125,26 @@ __contract__( assigns(memory_slice(state, sizeof(mld_shake128ctx))) ); +#define mld_shake128 FIPS202_NAMESPACE(shake128) +/************************************************* + * Name: mld_shake128 + * + * Description: SHAKE128 XOF with non-incremental API + * + * Arguments: - uint8_t *out: pointer to output + * - size_t outlen: requested output length in bytes + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(outlen <= 8 * SHAKE128_RATE /* somewhat arbitrary bound */) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); + #define mld_shake256_init FIPS202_NAMESPACE(shake256_init) /************************************************* * Name: mld_shake256_init @@ -231,4 +255,76 @@ __contract__( assigns(memory_slice(out, outlen)) ); +#define mld_sha3_256 FIPS202_NAMESPACE(sha3_256) +/************************************************* + * Name: mld_sha3_256 + * + * Description: SHA3-256 hash function + * + * Arguments: - uint8_t *out: pointer to output (32 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha3_256(uint8_t *out, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, SHA3_256_HASHBYTES)) + assigns(memory_slice(out, SHA3_256_HASHBYTES)) +); + +#define mld_sha3_384 FIPS202_NAMESPACE(sha3_384) +/************************************************* + * Name: mld_sha3_384 + * + * Description: SHA3-384 hash function + * + * Arguments: - uint8_t *out: pointer to output (48 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha3_384(uint8_t *out, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, SHA3_384_HASHBYTES)) + assigns(memory_slice(out, SHA3_384_HASHBYTES)) +); + +#define mld_sha3_224 FIPS202_NAMESPACE(sha3_224) +/************************************************* + * Name: mld_sha3_224 + * + * Description: SHA3-224 hash function + * + * Arguments: - uint8_t *out: pointer to output (28 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha3_224(uint8_t *out, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, SHA3_224_HASHBYTES)) + assigns(memory_slice(out, SHA3_224_HASHBYTES)) +); + +#define mld_sha3_512 FIPS202_NAMESPACE(sha3_512) +/************************************************* + * Name: mld_sha3_512 + * + * Description: SHA3-512 hash function + * + * Arguments: - uint8_t *out: pointer to output (64 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha3_512(uint8_t *out, const uint8_t *in, size_t inlen) +__contract__( + requires(inlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(in, inlen)) + requires(memory_no_alias(out, SHA3_512_HASHBYTES)) + assigns(memory_slice(out, SHA3_512_HASHBYTES)) +); + #endif /* !MLD_FIPS202_FIPS202_H */ diff --git a/mldsa/sha2/sha2.h b/mldsa/sha2/sha2.h new file mode 100644 index 000000000..91528d177 --- /dev/null +++ b/mldsa/sha2/sha2.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The slhdsa-c project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +#ifndef MLD_SHA2_SHA2_H +#define MLD_SHA2_SHA2_H + + +/* FIPS 180-4 (SHA-2) */ + +#include +#include +#include "../cbmc.h" + +#define SHA2_224_HASHBYTES 28 +#define SHA2_256_HASHBYTES 32 +#define SHA2_384_HASHBYTES 48 +#define SHA2_512_HASHBYTES 64 +#define SHA2_512_224_HASHBYTES 28 +#define SHA2_512_256_HASHBYTES 32 + +#define FIPS180_NAMESPACE(s) mldsa_fips180_ref_##s + +#define mld_sha2_224 FIPS180_NAMESPACE(sha2_224) +/************************************************* + * Name: mld_sha2_224 + * + * Description: SHA2-224 hash function + * + * Arguments: - uint8_t *out: pointer to output (28 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha2_224(uint8_t *out, const uint8_t *in, size_t inlen); + +#define mld_sha2_256 FIPS180_NAMESPACE(sha2_256) +/************************************************* + * Name: mld_sha2_256 + * + * Description: SHA2-256 hash function + * + * Arguments: - uint8_t *out: pointer to output (32 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha2_256(uint8_t *out, const uint8_t *in, size_t inlen); + +#define mld_sha2_384 FIPS180_NAMESPACE(sha2_384) +/************************************************* + * Name: mld_sha2_384 + * + * Description: SHA2-384 hash function + * + * Arguments: - uint8_t *out: pointer to output (48 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha2_384(uint8_t *out, const uint8_t *in, size_t inlen); + +#define mld_sha2_512 FIPS180_NAMESPACE(sha2_512) +/************************************************* + * Name: mld_sha2_512 + * + * Description: SHA2-512 hash function + * + * Arguments: - uint8_t *out: pointer to output (64 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha2_512(uint8_t *out, const uint8_t *in, size_t inlen); + +#define mld_sha2_512_224 FIPS180_NAMESPACE(sha2_512_224) +/************************************************* + * Name: mld_sha2_512_224 + * + * Description: SHA2-512/224 hash function + * + * Arguments: - uint8_t *out: pointer to output (28 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha2_512_224(uint8_t *out, const uint8_t *in, size_t inlen); + +#define mld_sha2_512_256 FIPS180_NAMESPACE(sha2_512_256) +/************************************************* + * Name: mld_sha2_512_256 + * + * Description: SHA2-512/256 hash function + * + * Arguments: - uint8_t *out: pointer to output (32 bytes) + * - const uint8_t *in: pointer to input + * - size_t inlen: length of input in bytes + **************************************************/ +void mld_sha2_512_256(uint8_t *out, const uint8_t *in, size_t inlen); + +#endif /* !MLD_SHA2_SHA2_H */ diff --git a/mldsa/sha2/sha2_256.c b/mldsa/sha2/sha2_256.c new file mode 100644 index 000000000..fab4c8fcc --- /dev/null +++ b/mldsa/sha2/sha2_256.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The slhdsa-c project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* FIPS 180-4 SHA2-256 / Portable C Implementation */ + +#include +#include + +#include "../common.h" +#include "sha2.h" + +/* Bitwise rotation macro */ +static MLD_INLINE uint32_t ror32(uint32_t x, uint32_t n) +{ + return (x >> n) | (x << (32 - n)); +} + +/* Byte reversal for big-endian */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define rev8_be32(x) (x) +#else +static MLD_INLINE uint32_t rev8_be32(uint32_t x) +{ + return ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24); +} +#endif /* __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */ + +/* SHA2-256 state structure */ +typedef struct +{ + uint32_t s[8 + 24]; + size_t i, len; +} sha2_256_t; + +/* processing step, sets "d" and "h" as a function of all 8 inputs */ +/* and message schedule "mi", round constant "ki" */ +#define STEP_SHA256_R(a, b, c, d, e, f, g, h, mi, ki) \ + { \ + h += (g ^ (e & (f ^ g))) + mi + ki + \ + (ror32(e, 6) ^ ror32(e, 11) ^ ror32(e, 25)); \ + d += h; \ + h += (((a | c) & b) | (c & a)) + \ + (ror32(a, 2) ^ ror32(a, 13) ^ ror32(a, 22)); \ + } + +/* keying step, sets x0 as a function of 4 inputs */ +#define STEP_SHA256_K(x0, x1, x9, xe) \ + { \ + x0 += x9 + (ror32(x1, 7) ^ ror32(x1, 18) ^ (x1 >> 3)) + \ + (ror32(xe, 17) ^ ror32(xe, 19) ^ (xe >> 10)); \ + } + +static void sha2_256_compress(void *v) +{ + /* 4.2.2 SHA-224 and SHA-256 Constants */ + const uint32_t ck[64] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, + 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, + 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, + 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, + 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, + 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2}; + + uint32_t a, b, c, d, e, f, g, h; + uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, ma, mb, mc, md, me, mf; + + uint32_t *sp = (uint32_t *)v; + const uint32_t *mp = sp + 8; + const uint32_t *kp = ck; + + a = sp[0] = rev8_be32(sp[0]); + b = sp[1] = rev8_be32(sp[1]); + c = sp[2] = rev8_be32(sp[2]); + d = sp[3] = rev8_be32(sp[3]); + e = sp[4] = rev8_be32(sp[4]); + f = sp[5] = rev8_be32(sp[5]); + g = sp[6] = rev8_be32(sp[6]); + h = sp[7] = rev8_be32(sp[7]); + + /* load and reverse bytes (if needed) */ + + m0 = rev8_be32(mp[0]); + m1 = rev8_be32(mp[1]); + m2 = rev8_be32(mp[2]); + m3 = rev8_be32(mp[3]); + m4 = rev8_be32(mp[4]); + m5 = rev8_be32(mp[5]); + m6 = rev8_be32(mp[6]); + m7 = rev8_be32(mp[7]); + m8 = rev8_be32(mp[8]); + m9 = rev8_be32(mp[9]); + ma = rev8_be32(mp[10]); + mb = rev8_be32(mp[11]); + mc = rev8_be32(mp[12]); + md = rev8_be32(mp[13]); + me = rev8_be32(mp[14]); + mf = rev8_be32(mp[15]); + + while (1) + { + STEP_SHA256_R(a, b, c, d, e, f, g, h, m0, kp[0]); /* rounds */ + STEP_SHA256_R(h, a, b, c, d, e, f, g, m1, kp[1]); + STEP_SHA256_R(g, h, a, b, c, d, e, f, m2, kp[2]); + STEP_SHA256_R(f, g, h, a, b, c, d, e, m3, kp[3]); + STEP_SHA256_R(e, f, g, h, a, b, c, d, m4, kp[4]); + STEP_SHA256_R(d, e, f, g, h, a, b, c, m5, kp[5]); + STEP_SHA256_R(c, d, e, f, g, h, a, b, m6, kp[6]); + STEP_SHA256_R(b, c, d, e, f, g, h, a, m7, kp[7]); + STEP_SHA256_R(a, b, c, d, e, f, g, h, m8, kp[8]); + STEP_SHA256_R(h, a, b, c, d, e, f, g, m9, kp[9]); + STEP_SHA256_R(g, h, a, b, c, d, e, f, ma, kp[10]); + STEP_SHA256_R(f, g, h, a, b, c, d, e, mb, kp[11]); + STEP_SHA256_R(e, f, g, h, a, b, c, d, mc, kp[12]); + STEP_SHA256_R(d, e, f, g, h, a, b, c, md, kp[13]); + STEP_SHA256_R(c, d, e, f, g, h, a, b, me, kp[14]); + STEP_SHA256_R(b, c, d, e, f, g, h, a, mf, kp[15]); + + if (kp == &ck[64 - 16]) + { + break; + } + kp += 16; + + STEP_SHA256_K(m0, m1, m9, me); /* message schedule */ + STEP_SHA256_K(m1, m2, ma, mf); + STEP_SHA256_K(m2, m3, mb, m0); + STEP_SHA256_K(m3, m4, mc, m1); + STEP_SHA256_K(m4, m5, md, m2); + STEP_SHA256_K(m5, m6, me, m3); + STEP_SHA256_K(m6, m7, mf, m4); + STEP_SHA256_K(m7, m8, m0, m5); + STEP_SHA256_K(m8, m9, m1, m6); + STEP_SHA256_K(m9, ma, m2, m7); + STEP_SHA256_K(ma, mb, m3, m8); + STEP_SHA256_K(mb, mc, m4, m9); + STEP_SHA256_K(mc, md, m5, ma); + STEP_SHA256_K(md, me, m6, mb); + STEP_SHA256_K(me, mf, m7, mc); + STEP_SHA256_K(mf, m0, m8, md); + } + + sp[0] = rev8_be32(sp[0] + a); + sp[1] = rev8_be32(sp[1] + b); + sp[2] = rev8_be32(sp[2] + c); + sp[3] = rev8_be32(sp[3] + d); + sp[4] = rev8_be32(sp[4] + e); + sp[5] = rev8_be32(sp[5] + f); + sp[6] = rev8_be32(sp[6] + g); + sp[7] = rev8_be32(sp[7] + h); +} + +/* initialize */ + +static void sha2_256_init_h0(sha2_256_t *sha, const uint8_t h0[32]) +{ + mld_memcpy(sha->s, h0, 32); + sha->i = 0; + sha->len = 0; +} + +static void sha2_256_init(sha2_256_t *sha) +{ + /* SHA-256 initial values H0, Sect 5.3.3. */ + const uint8_t sha2_256_h0[32] = { + 0x6A, 0x09, 0xE6, 0x67, 0xBB, 0x67, 0xAE, 0x85, 0x3C, 0x6E, 0xF3, + 0x72, 0xA5, 0x4F, 0xF5, 0x3A, 0x51, 0x0E, 0x52, 0x7F, 0x9B, 0x05, + 0x68, 0x8C, 0x1F, 0x83, 0xD9, 0xAB, 0x5B, 0xE0, 0xCD, 0x19}; + + sha2_256_init_h0(sha, sha2_256_h0); +} + +static void sha2_224_init(sha2_256_t *sha) +{ + /* SHA-224 initial values H0, Sect 5.3.2. */ + const uint8_t sha2_224_h0[32] = { + 0xC1, 0x05, 0x9E, 0xD8, 0x36, 0x7C, 0xD5, 0x07, 0x30, 0x70, 0xDD, + 0x17, 0xF7, 0x0E, 0x59, 0x39, 0xFF, 0xC0, 0x0B, 0x31, 0x68, 0x58, + 0x15, 0x11, 0x64, 0xF9, 0x8F, 0xA7, 0xBE, 0xFA, 0x4F, 0xA4}; + + sha2_256_init_h0(sha, sha2_224_h0); +} + +/* SHA2-256 process input */ + +static void sha2_256_update(sha2_256_t *sha, const uint8_t *m, size_t m_sz) +{ + size_t l; + uint8_t *mp = (uint8_t *)&sha->s[8]; + + sha->len += m_sz; + l = 64 - sha->i; + + if (m_sz < l) + { + mld_memcpy(mp + sha->i, m, m_sz); + sha->i += m_sz; + return; + } + if (sha->i > 0) + { + mld_memcpy(mp + sha->i, m, l); + sha2_256_compress(sha->s); + m_sz -= l; + m += l; + sha->i = 0; + } + while (m_sz >= 64) + { + mld_memcpy(mp, m, 64); + sha2_256_compress(sha->s); + m_sz -= 64; + m += 64; + } + mld_memcpy(mp, m, m_sz); + sha->i = m_sz; +} + +/* perform final padding */ + +static void sha2_256_final_pad(sha2_256_t *sha) +{ + uint8_t *mp = (uint8_t *)&sha->s[8]; + uint64_t x; + size_t i; + + i = sha->i; /* last data block */ + mp[i++] = 0x80; + if (i > 56) + { + mld_memset(mp + i, 0x00, 64 - i); + sha2_256_compress(sha->s); + i = 0; + } + mld_memset(mp + i, 0x00, 64 - i); /* clear rest */ + + x = ((uint64_t)sha->len) << 3; /* process length */ + i = 64; + while (x > 0) + { + mp[--i] = x & 0xFF; + x >>= 8; + } +} + +/* produce h_sz byte hash */ + +static void sha2_256_final(sha2_256_t *sha, uint8_t *h) +{ + sha2_256_final_pad(sha); + sha2_256_compress(sha->s); + + mld_memcpy(h, sha->s, 32); +} + +static void sha2_224_final(sha2_256_t *sha, uint8_t *h) +{ + sha2_256_final_pad(sha); + sha2_256_compress(sha->s); + + mld_memcpy(h, sha->s, 28); +} + +/* SHA-256 public single-call interface */ + +void mld_sha2_256(uint8_t *h, const uint8_t *m, size_t m_sz) +{ + sha2_256_t sha; + + sha2_256_init(&sha); + sha2_256_update(&sha, m, m_sz); + sha2_256_final(&sha, h); + mld_zeroize(&sha, sizeof(sha)); +} + +/* SHA-224 public single-call interface */ + +void mld_sha2_224(uint8_t *h, const uint8_t *m, size_t m_sz) +{ + sha2_256_t sha; + + sha2_224_init(&sha); + sha2_256_update(&sha, m, m_sz); + sha2_224_final(&sha, h); + mld_zeroize(&sha, sizeof(sha)); +} diff --git a/mldsa/sha2/sha2_512.c b/mldsa/sha2/sha2_512.c new file mode 100644 index 000000000..35ecbe537 --- /dev/null +++ b/mldsa/sha2/sha2_512.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) The mldsa-native project authors + * Copyright (c) The slhdsa-c project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* FIPS 180-4 SHA2-512 / Portable C Implementation */ + +#include +#include + +#include "../common.h" +#include "sha2.h" + +/* Bitwise rotation macro */ +static MLD_INLINE uint64_t ror64(uint64_t x, uint64_t n) +{ + return (x >> n) | (x << (64 - n)); +} + +/* Byte reversal for big-endian */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define rev8_be64(x) (x) +#else +static MLD_INLINE uint64_t rev8_be64(uint64_t x) +{ + return ((x & UINT64_C(0xFF00000000000000)) >> 56) | + ((x & UINT64_C(0x00FF000000000000)) >> 40) | + ((x & UINT64_C(0x0000FF0000000000)) >> 24) | + ((x & UINT64_C(0x000000FF00000000)) >> 8) | + ((x & UINT64_C(0x00000000FF000000)) << 8) | + ((x & UINT64_C(0x0000000000FF0000)) << 24) | + ((x & UINT64_C(0x000000000000FF00)) << 40) | + ((x & UINT64_C(0x00000000000000FF)) << 56); +} +#endif /* __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */ + +/* SHA2-512 state structure */ +typedef struct +{ + uint64_t s[8 + 16]; + size_t i, len; +} sha2_512_t; + +/* processing step, sets "d" and "h" as a function of all 8 inputs */ +/* and message schedule "mi", round constant "ki" */ +#define STEP_SHA512_R(a, b, c, d, e, f, g, h, mi, ki) \ + { \ + h += (g ^ (e & (f ^ g))) + mi + ki + \ + (ror64(e, 14) ^ ror64(e, 18) ^ ror64(e, 41)); \ + d += h; \ + h += (((a | c) & b) | (c & a)) + \ + (ror64(a, 28) ^ ror64(a, 34) ^ ror64(a, 39)); \ + } + +/* keying step, sets x0 as a function of 4 inputs */ +#define STEP_SHA512_K(x0, x1, x9, xe) \ + { \ + x0 += x9 + (ror64(x1, 1) ^ ror64(x1, 8) ^ (x1 >> 7)) + \ + (ror64(xe, 19) ^ ror64(xe, 61) ^ (xe >> 6)); \ + } + +static void sha2_512_compress(void *v) +{ + /* 4.2.3 SHA-384, SHA-512, SHA-512/224 and SHA-512/256 Constants */ + const uint64_t ck[80] = { + UINT64_C(0x428A2F98D728AE22), UINT64_C(0x7137449123EF65CD), + UINT64_C(0xB5C0FBCFEC4D3B2F), UINT64_C(0xE9B5DBA58189DBBC), + UINT64_C(0x3956C25BF348B538), UINT64_C(0x59F111F1B605D019), + UINT64_C(0x923F82A4AF194F9B), UINT64_C(0xAB1C5ED5DA6D8118), + UINT64_C(0xD807AA98A3030242), UINT64_C(0x12835B0145706FBE), + UINT64_C(0x243185BE4EE4B28C), UINT64_C(0x550C7DC3D5FFB4E2), + UINT64_C(0x72BE5D74F27B896F), UINT64_C(0x80DEB1FE3B1696B1), + UINT64_C(0x9BDC06A725C71235), UINT64_C(0xC19BF174CF692694), + UINT64_C(0xE49B69C19EF14AD2), UINT64_C(0xEFBE4786384F25E3), + UINT64_C(0x0FC19DC68B8CD5B5), UINT64_C(0x240CA1CC77AC9C65), + UINT64_C(0x2DE92C6F592B0275), UINT64_C(0x4A7484AA6EA6E483), + UINT64_C(0x5CB0A9DCBD41FBD4), UINT64_C(0x76F988DA831153B5), + UINT64_C(0x983E5152EE66DFAB), UINT64_C(0xA831C66D2DB43210), + UINT64_C(0xB00327C898FB213F), UINT64_C(0xBF597FC7BEEF0EE4), + UINT64_C(0xC6E00BF33DA88FC2), UINT64_C(0xD5A79147930AA725), + UINT64_C(0x06CA6351E003826F), UINT64_C(0x142929670A0E6E70), + UINT64_C(0x27B70A8546D22FFC), UINT64_C(0x2E1B21385C26C926), + UINT64_C(0x4D2C6DFC5AC42AED), UINT64_C(0x53380D139D95B3DF), + UINT64_C(0x650A73548BAF63DE), UINT64_C(0x766A0ABB3C77B2A8), + UINT64_C(0x81C2C92E47EDAEE6), UINT64_C(0x92722C851482353B), + UINT64_C(0xA2BFE8A14CF10364), UINT64_C(0xA81A664BBC423001), + UINT64_C(0xC24B8B70D0F89791), UINT64_C(0xC76C51A30654BE30), + UINT64_C(0xD192E819D6EF5218), UINT64_C(0xD69906245565A910), + UINT64_C(0xF40E35855771202A), UINT64_C(0x106AA07032BBD1B8), + UINT64_C(0x19A4C116B8D2D0C8), UINT64_C(0x1E376C085141AB53), + UINT64_C(0x2748774CDF8EEB99), UINT64_C(0x34B0BCB5E19B48A8), + UINT64_C(0x391C0CB3C5C95A63), UINT64_C(0x4ED8AA4AE3418ACB), + UINT64_C(0x5B9CCA4F7763E373), UINT64_C(0x682E6FF3D6B2B8A3), + UINT64_C(0x748F82EE5DEFB2FC), UINT64_C(0x78A5636F43172F60), + UINT64_C(0x84C87814A1F0AB72), UINT64_C(0x8CC702081A6439EC), + UINT64_C(0x90BEFFFA23631E28), UINT64_C(0xA4506CEBDE82BDE9), + UINT64_C(0xBEF9A3F7B2C67915), UINT64_C(0xC67178F2E372532B), + UINT64_C(0xCA273ECEEA26619C), UINT64_C(0xD186B8C721C0C207), + UINT64_C(0xEADA7DD6CDE0EB1E), UINT64_C(0xF57D4F7FEE6ED178), + UINT64_C(0x06F067AA72176FBA), UINT64_C(0x0A637DC5A2C898A6), + UINT64_C(0x113F9804BEF90DAE), UINT64_C(0x1B710B35131C471B), + UINT64_C(0x28DB77F523047D84), UINT64_C(0x32CAAB7B40C72493), + UINT64_C(0x3C9EBE0A15C9BEBC), UINT64_C(0x431D67C49C100D4C), + UINT64_C(0x4CC5D4BECB3E42B6), UINT64_C(0x597F299CFC657E2A), + UINT64_C(0x5FCB6FAB3AD6FAEC), UINT64_C(0x6C44198C4A475817)}; + + uint64_t a, b, c, d, e, f, g, h; + uint64_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, ma, mb, mc, md, me, mf; + + uint64_t *sp = (uint64_t *)v; + const uint64_t *mp = sp + 8; + const uint64_t *kp = ck; + + /* get state */ + a = sp[0] = rev8_be64(sp[0]); + b = sp[1] = rev8_be64(sp[1]); + c = sp[2] = rev8_be64(sp[2]); + d = sp[3] = rev8_be64(sp[3]); + e = sp[4] = rev8_be64(sp[4]); + f = sp[5] = rev8_be64(sp[5]); + g = sp[6] = rev8_be64(sp[6]); + h = sp[7] = rev8_be64(sp[7]); + + /* load and reverse bytes (if needed) */ + m0 = rev8_be64(mp[0]); + m1 = rev8_be64(mp[1]); + m2 = rev8_be64(mp[2]); + m3 = rev8_be64(mp[3]); + m4 = rev8_be64(mp[4]); + m5 = rev8_be64(mp[5]); + m6 = rev8_be64(mp[6]); + m7 = rev8_be64(mp[7]); + m8 = rev8_be64(mp[8]); + m9 = rev8_be64(mp[9]); + ma = rev8_be64(mp[10]); + mb = rev8_be64(mp[11]); + mc = rev8_be64(mp[12]); + md = rev8_be64(mp[13]); + me = rev8_be64(mp[14]); + mf = rev8_be64(mp[15]); + + while (1) + { + /* main rounds */ + STEP_SHA512_R(a, b, c, d, e, f, g, h, m0, kp[0]); + STEP_SHA512_R(h, a, b, c, d, e, f, g, m1, kp[1]); + STEP_SHA512_R(g, h, a, b, c, d, e, f, m2, kp[2]); + STEP_SHA512_R(f, g, h, a, b, c, d, e, m3, kp[3]); + STEP_SHA512_R(e, f, g, h, a, b, c, d, m4, kp[4]); + STEP_SHA512_R(d, e, f, g, h, a, b, c, m5, kp[5]); + STEP_SHA512_R(c, d, e, f, g, h, a, b, m6, kp[6]); + STEP_SHA512_R(b, c, d, e, f, g, h, a, m7, kp[7]); + STEP_SHA512_R(a, b, c, d, e, f, g, h, m8, kp[8]); + STEP_SHA512_R(h, a, b, c, d, e, f, g, m9, kp[9]); + STEP_SHA512_R(g, h, a, b, c, d, e, f, ma, kp[10]); + STEP_SHA512_R(f, g, h, a, b, c, d, e, mb, kp[11]); + STEP_SHA512_R(e, f, g, h, a, b, c, d, mc, kp[12]); + STEP_SHA512_R(d, e, f, g, h, a, b, c, md, kp[13]); + STEP_SHA512_R(c, d, e, f, g, h, a, b, me, kp[14]); + STEP_SHA512_R(b, c, d, e, f, g, h, a, mf, kp[15]); + + if (kp == &ck[80 - 16]) + { + break; + } + kp += 16; + + STEP_SHA512_K(m0, m1, m9, me); /* key schedule */ + STEP_SHA512_K(m1, m2, ma, mf); + STEP_SHA512_K(m2, m3, mb, m0); + STEP_SHA512_K(m3, m4, mc, m1); + STEP_SHA512_K(m4, m5, md, m2); + STEP_SHA512_K(m5, m6, me, m3); + STEP_SHA512_K(m6, m7, mf, m4); + STEP_SHA512_K(m7, m8, m0, m5); + STEP_SHA512_K(m8, m9, m1, m6); + STEP_SHA512_K(m9, ma, m2, m7); + STEP_SHA512_K(ma, mb, m3, m8); + STEP_SHA512_K(mb, mc, m4, m9); + STEP_SHA512_K(mc, md, m5, ma); + STEP_SHA512_K(md, me, m6, mb); + STEP_SHA512_K(me, mf, m7, mc); + STEP_SHA512_K(mf, m0, m8, md); + } + + sp[0] = rev8_be64(sp[0] + a); + sp[1] = rev8_be64(sp[1] + b); + sp[2] = rev8_be64(sp[2] + c); + sp[3] = rev8_be64(sp[3] + d); + sp[4] = rev8_be64(sp[4] + e); + sp[5] = rev8_be64(sp[5] + f); + sp[6] = rev8_be64(sp[6] + g); + sp[7] = rev8_be64(sp[7] + h); +} + +/* initialize */ + +static void sha2_512_init_h0(sha2_512_t *sha, const uint8_t h0[64]) +{ + mld_memcpy(sha->s, h0, 64); + sha->i = 0; + sha->len = 0; +} + +static void sha2_512_init(sha2_512_t *sha) +{ + /* SHA-512 initial values H0, Sect 5.3.5. */ + const uint8_t sha2_512_h0[64] = { + 0x6A, 0x09, 0xE6, 0x67, 0xF3, 0xBC, 0xC9, 0x08, 0xBB, 0x67, 0xAE, + 0x85, 0x84, 0xCA, 0xA7, 0x3B, 0x3C, 0x6E, 0xF3, 0x72, 0xFE, 0x94, + 0xF8, 0x2B, 0xA5, 0x4F, 0xF5, 0x3A, 0x5F, 0x1D, 0x36, 0xF1, 0x51, + 0x0E, 0x52, 0x7F, 0xAD, 0xE6, 0x82, 0xD1, 0x9B, 0x05, 0x68, 0x8C, + 0x2B, 0x3E, 0x6C, 0x1F, 0x1F, 0x83, 0xD9, 0xAB, 0xFB, 0x41, 0xBD, + 0x6B, 0x5B, 0xE0, 0xCD, 0x19, 0x13, 0x7E, 0x21, 0x79}; + + sha2_512_init_h0(sha, sha2_512_h0); +} + +static void sha2_384_init(sha2_512_t *sha) +{ + /* SHA-384 initial values H0, Sect 5.3.4. */ + const uint8_t sha2_384_h0[64] = { + 0xCB, 0xBB, 0x9D, 0x5D, 0xC1, 0x05, 0x9E, 0xD8, 0x62, 0x9A, 0x29, + 0x2A, 0x36, 0x7C, 0xD5, 0x07, 0x91, 0x59, 0x01, 0x5A, 0x30, 0x70, + 0xDD, 0x17, 0x15, 0x2F, 0xEC, 0xD8, 0xF7, 0x0E, 0x59, 0x39, 0x67, + 0x33, 0x26, 0x67, 0xFF, 0xC0, 0x0B, 0x31, 0x8E, 0xB4, 0x4A, 0x87, + 0x68, 0x58, 0x15, 0x11, 0xDB, 0x0C, 0x2E, 0x0D, 0x64, 0xF9, 0x8F, + 0xA7, 0x47, 0xB5, 0x48, 0x1D, 0xBE, 0xFA, 0x4F, 0xA4}; + + sha2_512_init_h0(sha, sha2_384_h0); +} + +static void sha2_512_224_init(sha2_512_t *sha) +{ + /* SHA-512/224 initial values H0, Sect 5.3.6.1. */ + const uint8_t sha2_512_224_h0[64] = { + 0x8C, 0x3D, 0x37, 0xC8, 0x19, 0x54, 0x4D, 0xA2, 0x73, 0xE1, 0x99, + 0x66, 0x89, 0xDC, 0xD4, 0xD6, 0x1D, 0xFA, 0xB7, 0xAE, 0x32, 0xFF, + 0x9C, 0x82, 0x67, 0x9D, 0xD5, 0x14, 0x58, 0x2F, 0x9F, 0xCF, 0x0F, + 0x6D, 0x2B, 0x69, 0x7B, 0xD4, 0x4D, 0xA8, 0x77, 0xE3, 0x6F, 0x73, + 0x04, 0xC4, 0x89, 0x42, 0x3F, 0x9D, 0x85, 0xA8, 0x6A, 0x1D, 0x36, + 0xC8, 0x11, 0x12, 0xE6, 0xAD, 0x91, 0xD6, 0x92, 0xA1}; + + sha2_512_init_h0(sha, sha2_512_224_h0); +} + +static void sha2_512_256_init(sha2_512_t *sha) +{ + /* SHA-512/256 initial values H0, Sect 5.3.6.2. */ + const uint8_t sha2_512_256_h0[64] = { + 0x22, 0x31, 0x21, 0x94, 0xFC, 0x2B, 0xF7, 0x2C, 0x9F, 0x55, 0x5F, + 0xA3, 0xC8, 0x4C, 0x64, 0xC2, 0x23, 0x93, 0xB8, 0x6B, 0x6F, 0x53, + 0xB1, 0x51, 0x96, 0x38, 0x77, 0x19, 0x59, 0x40, 0xEA, 0xBD, 0x96, + 0x28, 0x3E, 0xE2, 0xA8, 0x8E, 0xFF, 0xE3, 0xBE, 0x5E, 0x1E, 0x25, + 0x53, 0x86, 0x39, 0x92, 0x2B, 0x01, 0x99, 0xFC, 0x2C, 0x85, 0xB8, + 0xAA, 0x0E, 0xB7, 0x2D, 0xDC, 0x81, 0xC5, 0x2C, 0xA2}; + + sha2_512_init_h0(sha, sha2_512_256_h0); +} + +/* SHA2-512 process input */ + +static void sha2_512_update(sha2_512_t *sha, const uint8_t *m, size_t m_sz) +{ + size_t l; + uint8_t *mp = (uint8_t *)&sha->s[8]; + + sha->len += m_sz; + l = 128 - sha->i; + + if (m_sz < l) + { + mld_memcpy(mp + sha->i, m, m_sz); + sha->i += m_sz; + return; + } + if (sha->i > 0) + { + mld_memcpy(mp + sha->i, m, l); + sha2_512_compress(sha->s); + m_sz -= l; + m += l; + sha->i = 0; + } + while (m_sz >= 128) + { + mld_memcpy(mp, m, 128); + sha2_512_compress(sha->s); + m_sz -= 128; + m += 128; + } + mld_memcpy(mp, m, m_sz); + sha->i = m_sz; +} + +/* perform final padding */ + +static void sha2_512_final_pad(sha2_512_t *sha) +{ + uint8_t *mp = (uint8_t *)&sha->s[8]; + uint64_t x; + size_t i; + + i = sha->i; /* last data block */ + mp[i++] = 0x80; + if (i > 112) + { + mld_memset(mp + i, 0x00, 128 - i); + sha2_512_compress(sha->s); + i = 0; + } + mld_memset(mp + i, 0x00, 128 - i); /* clear rest */ + + x = ((uint64_t)sha->len) << 3; /* process length */ + i = 128; + while (x > 0) + { + mp[--i] = x & 0xFF; + x >>= 8; + } +} + +/* produce h_sz byte hash */ + +static void sha2_512_final_len(sha2_512_t *sha, uint8_t *h, size_t h_sz) +{ + sha2_512_final_pad(sha); + sha2_512_compress(sha->s); + mld_memcpy(h, sha->s, h_sz); +} + +static void sha2_512_final(sha2_512_t *sha, uint8_t *h) +{ + sha2_512_final_len(sha, h, 64); +} + +static void sha2_384_final(sha2_512_t *sha, uint8_t *h) +{ + sha2_512_final_len(sha, h, 48); +} + +static void sha2_512_224_final(sha2_512_t *sha, uint8_t *h) +{ + sha2_512_final_len(sha, h, 28); +} + +static void sha2_512_256_final(sha2_512_t *sha, uint8_t *h) +{ + sha2_512_final_len(sha, h, 32); +} + +/* SHA-512 public single-call interface */ + +void mld_sha2_512(uint8_t *h, const uint8_t *m, size_t m_sz) +{ + sha2_512_t sha; + + sha2_512_init(&sha); + sha2_512_update(&sha, m, m_sz); + sha2_512_final(&sha, h); + mld_zeroize(&sha, sizeof(sha)); +} + +/* SHA-384 public single-call interface */ + +void mld_sha2_384(uint8_t *h, const uint8_t *m, size_t m_sz) +{ + sha2_512_t sha; + + sha2_384_init(&sha); + sha2_512_update(&sha, m, m_sz); + sha2_384_final(&sha, h); + mld_zeroize(&sha, sizeof(sha)); +} + +/* SHA-512/224 public single-call interface */ + +void mld_sha2_512_224(uint8_t *h, const uint8_t *m, size_t m_sz) +{ + sha2_512_t sha; + + sha2_512_224_init(&sha); + sha2_512_update(&sha, m, m_sz); + sha2_512_224_final(&sha, h); + mld_zeroize(&sha, sizeof(sha)); +} + +/* SHA-512/256 public single-call interface */ + +void mld_sha2_512_256(uint8_t *h, const uint8_t *m, size_t m_sz) +{ + sha2_512_t sha; + + sha2_512_256_init(&sha); + sha2_512_update(&sha, m, m_sz); + sha2_512_256_final(&sha, h); + mld_zeroize(&sha, sizeof(sha)); +} diff --git a/mldsa/sign.c b/mldsa/sign.c index f129046d4..ce6b99c64 100644 --- a/mldsa/sign.c +++ b/mldsa/sign.c @@ -32,6 +32,7 @@ #include "poly.h" #include "polyvec.h" #include "randombytes.h" +#include "sha2/sha2.h" #include "sign.h" #include "symmetric.h" @@ -862,3 +863,197 @@ int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, return -1; } + +/************************************************* + * Name: prehash_message + * + * Description: Computes the pre-hash of a message and writes both the OID + * and the pre-hash to a single output buffer. + * Output format: oid (11 bytes) || pre-hash + * + * Arguments: - uint8_t *out: pointer to output buffer (min 11 + 64 bytes) + * - size_t *oid_ph_len: pointer to output length (OID + pre-hash) + * - const uint8_t *m: pointer to input message + * - size_t mlen: length of input message + * - mld_hash_alg_t hashAlg: hash algorithm enumeration + * + * Returns 0 if hash algorithm is supported and -1 otherwise. + * Currently SHAKE-128 and SHAKE-256 are supported. + **************************************************/ +static int prehash_message(uint8_t *out, size_t *oid_ph_len, const uint8_t *m, + size_t mlen, mld_hash_alg_t hashAlg) +{ + /* OIDs for supported hash functions */ + const uint8_t shake_128_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x0B}; + const uint8_t shake_256_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x0C}; + const uint8_t sha3_256_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x08}; + const uint8_t sha3_224_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x07}; + const uint8_t sha3_384_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x09}; + const uint8_t sha3_512_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x0A}; + const uint8_t sha2_224_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x04}; + const uint8_t sha2_256_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x01}; + const uint8_t sha2_384_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x02}; + const uint8_t sha2_512_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x03}; + const uint8_t sha2_512_224_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x05}; + const uint8_t sha2_512_256_oid[11] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x06}; + + switch (hashAlg) + { + case MLD_SHAKE_128: + mld_memcpy(out, shake_128_oid, 11); + mld_shake128(out + 11, 32, m, mlen); + *oid_ph_len = 11 + 32; + return 0; + + case MLD_SHAKE_256: + mld_memcpy(out, shake_256_oid, 11); + mld_shake256(out + 11, 64, m, mlen); + *oid_ph_len = 11 + 64; + return 0; + + case MLD_SHA3_256: + mld_memcpy(out, sha3_256_oid, 11); + mld_sha3_256(out + 11, m, mlen); + *oid_ph_len = 11 + 32; + return 0; + + case MLD_SHA3_224: + mld_memcpy(out, sha3_224_oid, 11); + mld_sha3_224(out + 11, m, mlen); + *oid_ph_len = 11 + 28; + return 0; + + case MLD_SHA3_384: + mld_memcpy(out, sha3_384_oid, 11); + mld_sha3_384(out + 11, m, mlen); + *oid_ph_len = 11 + 48; + return 0; + + case MLD_SHA3_512: + mld_memcpy(out, sha3_512_oid, 11); + mld_sha3_512(out + 11, m, mlen); + *oid_ph_len = 11 + 64; + return 0; + + case MLD_SHA2_224: + mld_memcpy(out, sha2_224_oid, 11); + mld_sha2_224(out + 11, m, mlen); + *oid_ph_len = 11 + 28; + return 0; + + case MLD_SHA2_256: + mld_memcpy(out, sha2_256_oid, 11); + mld_sha2_256(out + 11, m, mlen); + *oid_ph_len = 11 + 32; + return 0; + + case MLD_SHA2_384: + mld_memcpy(out, sha2_384_oid, 11); + mld_sha2_384(out + 11, m, mlen); + *oid_ph_len = 11 + 48; + return 0; + + case MLD_SHA2_512: + mld_memcpy(out, sha2_512_oid, 11); + mld_sha2_512(out + 11, m, mlen); + *oid_ph_len = 11 + 64; + return 0; + + case MLD_SHA2_512_224: + mld_memcpy(out, sha2_512_224_oid, 11); + mld_sha2_512_224(out + 11, m, mlen); + *oid_ph_len = 11 + 28; + return 0; + + case MLD_SHA2_512_256: + mld_memcpy(out, sha2_512_256_oid, 11); + mld_sha2_512_256(out + 11, m, mlen); + *oid_ph_len = 11 + 32; + return 0; + + default: + return -1; + } + return -1; +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int crypto_sign_signature_pre_hash(uint8_t *sig, size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t *sk, mld_hash_alg_t hashAlg) +{ + /* formatted message: 0x01 || ctxlen (1 byte) || ctx || oid || ph */ + uint8_t fmsg[2 + 255 + 11 + 64]; + size_t oid_ph_len; + + if (ctxlen > 255) + { + *siglen = 0; + return -1; + } + + fmsg[0] = 1; + fmsg[1] = ctxlen; + if (ctx != NULL && ctxlen != 0) + { + mld_memcpy(fmsg + 2, ctx, ctxlen); + } + + /* Compute OID and pre-hash: writes oid || ph */ + if (prehash_message(fmsg + 2 + ctxlen, &oid_ph_len, m, mlen, hashAlg)) + { + *siglen = 0; + return -1; + } + + return crypto_sign_signature_internal( + sig, siglen, fmsg, 2 + ctxlen + oid_ph_len, NULL, 0, rnd, sk, 0); +} + +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int crypto_sign_verify_pre_hash(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t *pk, mld_hash_alg_t hashAlg) +{ + /* formatted message: 0x01 || ctxlen (1 byte) || ctx || oid || ph */ + uint8_t fmsg[2 + 255 + 11 + 64]; + size_t oid_ph_len; + + if (ctxlen > 255) + { + return -1; + } + + fmsg[0] = 1; + fmsg[1] = ctxlen; + if (ctx != NULL && ctxlen != 0) + { + mld_memcpy(fmsg + 2, ctx, ctxlen); + } + + /* Compute OID and pre-hash: writes oid || ph */ + if (prehash_message(fmsg + 2 + ctxlen, &oid_ph_len, m, mlen, hashAlg)) + { + return -1; + } + + return crypto_sign_verify_internal(sig, siglen, fmsg, 2 + ctxlen + oid_ph_len, + NULL, 0, pk, 0); +} diff --git a/mldsa/sign.h b/mldsa/sign.h index 0024afca7..2be881622 100644 --- a/mldsa/sign.h +++ b/mldsa/sign.h @@ -23,6 +23,25 @@ #include "polyvec.h" #include "sys.h" +/************************************************* + * Hash algorithm enumeration for pre-hash functions + **************************************************/ +typedef enum +{ + MLD_SHA2_224, + MLD_SHA2_256, + MLD_SHA2_384, + MLD_SHA2_512, + MLD_SHA2_512_224, + MLD_SHA2_512_256, + MLD_SHA3_224, + MLD_SHA3_256, + MLD_SHA3_384, + MLD_SHA3_512, + MLD_SHAKE_128, + MLD_SHAKE_256 +} mld_hash_alg_t; + #define crypto_sign_keypair_internal MLD_NAMESPACE(keypair_internal) /************************************************* * Name: crypto_sign_keypair_internal @@ -382,4 +401,87 @@ __contract__( ensures(return_value == 0 || return_value == -1) ); + +#define crypto_sign_signature_pre_hash MLD_NAMESPACE(signature_pre_hash) +/************************************************* + * Name: crypto_sign_signature_pre_hash + * + * Description: FIPS 204: Algorithm 4 HashML-DSA.Sign. + * Computes signature with pre-hashed message. + * The message is hashed internally. + * + * Arguments: - uint8_t *sig: pointer to output signature (of length + * CRYPTO_BYTES) + * - size_t *siglen: pointer to output length of signature + * - const uint8_t *m: pointer to message to be hashed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t *rnd: pointer to random seed + * - const uint8_t *sk: pointer to bit-packed secret key + * - mld_hash_alg_t hashAlg: hash algorithm enumeration + * + * Returns 0 (success) or -1 (context string too long OR nonce exhaustion OR + *unsupported hash) + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int crypto_sign_signature_pre_hash(uint8_t *sig, size_t *siglen, + const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t rnd[MLDSA_RNDBYTES], + const uint8_t *sk, mld_hash_alg_t hashAlg) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, CRYPTO_BYTES)) + requires(memory_no_alias(siglen, sizeof(size_t))) + requires(memory_no_alias(m, mlen)) + requires((ctx == NULL && ctxlen == 0) || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(rnd, MLDSA_RNDBYTES)) + requires(memory_no_alias(sk, CRYPTO_SECRETKEYBYTES)) + requires(hashAlg >= MLD_SHA2_224 && hashAlg <= MLD_SHAKE_256) + assigns(memory_slice(sig, CRYPTO_BYTES)) + assigns(object_whole(siglen)) + ensures((return_value == 0 && *siglen == CRYPTO_BYTES) || + (return_value == -1 && *siglen == 0)) +); + +#define crypto_sign_verify_pre_hash MLD_NAMESPACE(verify_pre_hash) +/************************************************* + * Name: crypto_sign_verify_pre_hash + * + * Description: FIPS 204: Algorithm 5 HashML-DSA.Verify. + * Verifies signature with pre-hashed message. + * The message is hashed internally. + * + * Arguments: - const uint8_t *sig: pointer to input signature + * - size_t siglen: length of signature + * - const uint8_t *m: pointer to message to be hashed + * - size_t mlen: length of message + * - const uint8_t *ctx: pointer to context string + * - size_t ctxlen: length of context string + * - const uint8_t *pk: pointer to bit-packed public key + * - mld_hash_alg_t hashAlg: hash algorithm enumeration + * + * Returns 0 if signature could be verified correctly and -1 otherwise + **************************************************/ +MLD_MUST_CHECK_RETURN_VALUE +MLD_EXTERNAL_API +int crypto_sign_verify_pre_hash(const uint8_t *sig, size_t siglen, + const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, + const uint8_t *pk, mld_hash_alg_t hashAlg) +__contract__( + requires(mlen <= MLD_MAX_BUFFER_SIZE) + requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77) + requires(siglen <= MLD_MAX_BUFFER_SIZE) + requires(memory_no_alias(sig, siglen)) + requires(memory_no_alias(m, mlen)) + requires((ctx == NULL && ctxlen == 0) || memory_no_alias(ctx, ctxlen)) + requires(memory_no_alias(pk, CRYPTO_PUBLICKEYBYTES)) + requires(hashAlg >= MLD_SHA2_224 && hashAlg <= MLD_SHAKE_256) + ensures(return_value == 0 || return_value == -1) +); + #endif /* !MLD_SIGN_H */ diff --git a/proofs/cbmc/crypto_sign_signature_pre_hash/Makefile b/proofs/cbmc/crypto_sign_signature_pre_hash/Makefile new file mode 100644 index 000000000..26a01830b --- /dev/null +++ b/proofs/cbmc/crypto_sign_signature_pre_hash/Makefile @@ -0,0 +1,58 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = crypto_sign_signature_pre_hash_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = crypto_sign_signature_pre_hash + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_pre_hash +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)signature_internal + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = crypto_sign_signature_pre_hash + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/crypto_sign_signature_pre_hash/crypto_sign_signature_pre_hash_harness.c b/proofs/cbmc/crypto_sign_signature_pre_hash/crypto_sign_signature_pre_hash_harness.c new file mode 100644 index 000000000..a880ea960 --- /dev/null +++ b/proofs/cbmc/crypto_sign_signature_pre_hash/crypto_sign_signature_pre_hash_harness.c @@ -0,0 +1,20 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + uint8_t *sig; + size_t *siglen; + const uint8_t *ph; + size_t phlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *rnd; + const uint8_t *sk; + mld_hash_alg_t hashAlg; + int r; + r = crypto_sign_signature_pre_hash(sig, siglen, ph, phlen, ctx, ctxlen, rnd, + sk, hashAlg); +} diff --git a/proofs/cbmc/crypto_sign_verify_pre_hash/Makefile b/proofs/cbmc/crypto_sign_verify_pre_hash/Makefile new file mode 100644 index 000000000..2f7739672 --- /dev/null +++ b/proofs/cbmc/crypto_sign_verify_pre_hash/Makefile @@ -0,0 +1,66 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = crypto_sign_verify_pre_hash_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = crypto_sign_verify_pre_hash + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/sign.c + +CHECK_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_pre_hash +USE_FUNCTION_CONTRACTS=$(MLD_NAMESPACE)verify_internal \ + $(MLD_NAMESPACE)unpack_pk \ + $(MLD_NAMESPACE)unpack_sig \ + $(MLD_NAMESPACE)polyvec_matrix_expand \ + $(MLD_NAMESPACE)polyvecl_invntt_tomont \ + $(MLD_NAMESPACE)polyveck_invntt_tomont \ + $(MLD_NAMESPACE)polyveck_sub \ + $(MLD_NAMESPACE)polyveck_use_hint +USE_FUNCTION_CONTRACTS+=mld_zeroize + +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 +CBMCFLAGS += --slice-formula +CBMCFLAGS += --no-array-field-sensitivity + +FUNCTION_NAME = crypto_sign_verify_pre_hash + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/crypto_sign_verify_pre_hash/crypto_sign_verify_pre_hash_harness.c b/proofs/cbmc/crypto_sign_verify_pre_hash/crypto_sign_verify_pre_hash_harness.c new file mode 100644 index 000000000..7b4752e17 --- /dev/null +++ b/proofs/cbmc/crypto_sign_verify_pre_hash/crypto_sign_verify_pre_hash_harness.c @@ -0,0 +1,19 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "sign.h" + +void harness(void) +{ + const uint8_t *sig; + size_t siglen; + const uint8_t *ph; + size_t phlen; + const uint8_t *ctx; + size_t ctxlen; + const uint8_t *pk; + mld_hash_alg_t hashAlg; + int r; + r = crypto_sign_verify_pre_hash(sig, siglen, ph, phlen, ctx, ctxlen, pk, + hashAlg); +} diff --git a/proofs/cbmc/sha3_224/Makefile b/proofs/cbmc/sha3_224/Makefile new file mode 100644 index 000000000..e7cf87d72 --- /dev/null +++ b/proofs/cbmc/sha3_224/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sha3_224_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sha3_224 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)sha3_224 +USE_FUNCTION_CONTRACTS=keccak_init keccak_absorb keccak_finalize keccak_squeeze +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = sha3_224 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/sha3_224/sha3_224_harness.c b/proofs/cbmc/sha3_224/sha3_224_harness.c new file mode 100644 index 000000000..fbeb25cdd --- /dev/null +++ b/proofs/cbmc/sha3_224/sha3_224_harness.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * Proof for mld_sha3_224() + */ + +#include +#include + +#include "fips202.h" + +void harness(void) +{ + uint8_t in[65536]; + uint8_t out[28]; + size_t inlen; + + mld_sha3_224(out, in, inlen); +} diff --git a/proofs/cbmc/sha3_256/Makefile b/proofs/cbmc/sha3_256/Makefile new file mode 100644 index 000000000..2cea5d40f --- /dev/null +++ b/proofs/cbmc/sha3_256/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sha3_256_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sha3_256 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)sha3_256 +USE_FUNCTION_CONTRACTS=keccak_init keccak_absorb keccak_finalize keccak_squeeze +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = sha3_256 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/sha3_256/sha3_256_harness.c b/proofs/cbmc/sha3_256/sha3_256_harness.c new file mode 100644 index 000000000..8ec93bc83 --- /dev/null +++ b/proofs/cbmc/sha3_256/sha3_256_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + uint8_t *out; + const uint8_t *in; + size_t inlen; + + mld_sha3_256(out, in, inlen); +} diff --git a/proofs/cbmc/sha3_384/Makefile b/proofs/cbmc/sha3_384/Makefile new file mode 100644 index 000000000..737cb87b2 --- /dev/null +++ b/proofs/cbmc/sha3_384/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sha3_384_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sha3_384 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)sha3_384 +USE_FUNCTION_CONTRACTS=keccak_init keccak_absorb keccak_finalize keccak_squeeze +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = sha3_384 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/sha3_384/sha3_384_harness.c b/proofs/cbmc/sha3_384/sha3_384_harness.c new file mode 100644 index 000000000..9960804aa --- /dev/null +++ b/proofs/cbmc/sha3_384/sha3_384_harness.c @@ -0,0 +1,13 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + uint8_t *out; + const uint8_t *in; + size_t inlen; + + mld_sha3_384(out, in, inlen); +} diff --git a/proofs/cbmc/sha3_512/Makefile b/proofs/cbmc/sha3_512/Makefile new file mode 100644 index 000000000..4daaf59d4 --- /dev/null +++ b/proofs/cbmc/sha3_512/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = sha3_512_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = sha3_512 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)sha3_512 +USE_FUNCTION_CONTRACTS=keccak_init keccak_absorb keccak_finalize keccak_squeeze +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = sha3_512 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/sha3_512/sha3_512_harness.c b/proofs/cbmc/sha3_512/sha3_512_harness.c new file mode 100644 index 000000000..cfcba7460 --- /dev/null +++ b/proofs/cbmc/sha3_512/sha3_512_harness.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) The mldsa-native project authors + * SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + */ + +/* + * Proof for mld_sha3_512() + */ + +#include +#include + +#include "fips202.h" + +void harness(void) +{ + uint8_t in[65536]; + uint8_t out[64]; + size_t inlen; + + mld_sha3_512(out, in, inlen); +} diff --git a/proofs/cbmc/shake128/Makefile b/proofs/cbmc/shake128/Makefile new file mode 100644 index 000000000..865de7fc2 --- /dev/null +++ b/proofs/cbmc/shake128/Makefile @@ -0,0 +1,55 @@ +# Copyright (c) The mldsa-native project authors +# SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = shake128_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = shake128 + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mldsa/fips202/fips202.c + +CHECK_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)shake128 +USE_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)shake128_init $(FIPS202_NAMESPACE)shake128_absorb $(FIPS202_NAMESPACE)shake128_finalize $(FIPS202_NAMESPACE)shake128_squeeze $(FIPS202_NAMESPACE)shake128_release +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = shake128 + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 8 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mldsa/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mldsa/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/proofs/cbmc/shake128/shake128_harness.c b/proofs/cbmc/shake128/shake128_harness.c new file mode 100644 index 000000000..ece260004 --- /dev/null +++ b/proofs/cbmc/shake128/shake128_harness.c @@ -0,0 +1,14 @@ +// Copyright (c) The mldsa-native project authors +// SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT + +#include "fips202/fips202.h" + +void harness(void) +{ + uint8_t *out; + size_t outlen; + const uint8_t *in; + size_t inlen; + + mld_shake128(out, outlen, in, inlen); +} diff --git a/test/acvp_client.py b/test/acvp_client.py index 224039261..1ccc63de1 100644 --- a/test/acvp_client.py +++ b/test/acvp_client.py @@ -135,19 +135,24 @@ def run_sigGen_test(tg, tc): assert tg["testType"] == "AFT" - # TODO: implement pre-hashing mode - if tg["preHash"] == "preHash": - info("SKIP preHash") - return - # TODO: probably we want to handle handle the deterministic case differently if tg["deterministic"] is True: tc["rnd"] = "0" * 64 - assert tc["hashAlg"] == "none" - - if tg["signatureInterface"] == "external": + if tg["preHash"] == "preHash": + assert len(tc["context"]) <= 2 * 255 + acvp_call = exec_prefix + [ + acvp_bin, + "sigGenPreHash", + f"message={tc['message']}", + f"context={tc['context']}", + f"rng={tc['rnd']}", + f"sk={tc['sk']}", + f"hashAlg={tc['hashAlg']}", + ] + elif tg["signatureInterface"] == "external": + assert tc["hashAlg"] == "none" assert len(tc["context"]) <= 2 * 255 assert len(tc["message"]) <= 2 * 65536 @@ -160,6 +165,7 @@ def run_sigGen_test(tg, tc): f"context={tc['context']}", ] else: # signatureInterface=internal + assert tc["hashAlg"] == "none" externalMu = 0 if tg["externalMu"] is True: externalMu = 1 @@ -198,13 +204,20 @@ def run_sigVer_test(tg, tc): info(f"Running sigVer test case {tc['tcId']} ... ", end="") acvp_bin = get_acvp_binary(tg) - # TODO: implement pre-hashing mode if tg["preHash"] == "preHash": - info("SKIP preHash") - return + assert len(tc["context"]) <= 2 * 255 - assert tc["hashAlg"] == "none" - if tg["signatureInterface"] == "external": + acvp_call = exec_prefix + [ + acvp_bin, + "sigVerPreHash", + f"message={tc['message']}", + f"context={tc['context']}", + f"signature={tc['signature']}", + f"pk={tc['pk']}", + f"hashAlg={tc['hashAlg']}", + ] + elif tg["signatureInterface"] == "external": + assert tc["hashAlg"] == "none" assert len(tc["context"]) <= 2 * 255 assert len(tc["message"]) <= 2 * 65536 @@ -217,6 +230,7 @@ def run_sigVer_test(tg, tc): f"pk={tc['pk']}", ] else: # signatureInterface=internal + assert tc["hashAlg"] == "none" externalMu = 0 if tg["externalMu"] is True: externalMu = 1 diff --git a/test/acvp_mldsa.c b/test/acvp_mldsa.c index 049ef3143..412cf78ea 100644 --- a/test/acvp_mldsa.c +++ b/test/acvp_mldsa.c @@ -21,6 +21,14 @@ #define SIGVER_INTERNAL_USAGE \ "acvp_mldsa{lvl} sigVerInternal message=HEX signature=HEX pk=HEX " \ "externalMu=0/1" +#define SIGGEN_PREHASH_USAGE \ + "acvp_mldsa{lvl} sigGenPreHash message=HEX context=HEX rng=HEX sk=HEX " \ + "hashAlg=STRING" +#define SIGVER_PREHASH_USAGE \ + "acvp_mldsa{lvl} sigVerPreHash message=HEX context=HEX signature=HEX " \ + "pk=HEX " \ + "hashAlg=STRING" + /* maximum message length used in the ACVP tests */ #define MAX_MSG_LENGTH 65536 @@ -45,7 +53,9 @@ typedef enum sigGen, sigGenInternal, sigVer, - sigVerInternal + sigVerInternal, + sigGenPreHash, + sigVerPreHash } acvp_mode; /* Decode hex character [0-9A-Fa-f] into 0-15 */ @@ -163,6 +173,45 @@ static int decode_keyed_int(const char *prefix_string, int *out, return 1; } +static int parse_str(const char *prefix, char *out, size_t out_max_len, + const char *str) +{ + size_t str_len = strlen(str); + size_t prefix_len = strlen(prefix); + size_t value_len; + + /* + * Check that str starts with `prefix=` + * Use memcmp, not strcmp + */ + if (str_len < prefix_len + 1 || memcmp(prefix, str, prefix_len) != 0 || + str[prefix_len] != '=') + { + goto str_usage; + } + + str += prefix_len + 1; + value_len = strlen(str); + + if (value_len >= out_max_len) + { + fprintf(stderr, + "Argument %s invalid: String value too long (max %u characters)\n", + str - prefix_len - 1, (unsigned)(out_max_len - 1)); + return 1; + } + + strncpy(out, str, out_max_len - 1); + out[out_max_len - 1] = '\0'; + return 0; + +str_usage: + fprintf(stderr, + "Argument %s invalid: Expected argument of the form '%s=STRING'\n", + str, prefix); + return 1; +} + static void print_hex(const char *name, const unsigned char *raw, size_t len) { if (name != NULL) @@ -245,6 +294,90 @@ static int acvp_mldsa_sigVerInternal_AFT( } } +static mld_hash_alg_t str_to_hash_alg(const char *hashAlg) +{ + if (strcmp(hashAlg, "SHA2-224") == 0) + { + return MLD_SHA2_224; + } + if (strcmp(hashAlg, "SHA2-256") == 0) + { + return MLD_SHA2_256; + } + if (strcmp(hashAlg, "SHA2-384") == 0) + { + return MLD_SHA2_384; + } + if (strcmp(hashAlg, "SHA2-512") == 0) + { + return MLD_SHA2_512; + } + if (strcmp(hashAlg, "SHA2-512/224") == 0) + { + return MLD_SHA2_512_224; + } + if (strcmp(hashAlg, "SHA2-512/256") == 0) + { + return MLD_SHA2_512_256; + } + if (strcmp(hashAlg, "SHA3-224") == 0) + { + return MLD_SHA3_224; + } + if (strcmp(hashAlg, "SHA3-256") == 0) + { + return MLD_SHA3_256; + } + if (strcmp(hashAlg, "SHA3-384") == 0) + { + return MLD_SHA3_384; + } + if (strcmp(hashAlg, "SHA3-512") == 0) + { + return MLD_SHA3_512; + } + if (strcmp(hashAlg, "SHAKE-128") == 0) + { + return MLD_SHAKE_128; + } + if (strcmp(hashAlg, "SHAKE-256") == 0) + { + return MLD_SHAKE_256; + } + /* Invalid hash algorithm */ + fprintf(stderr, "Error: Unsupported hash algorithm: %s\n", hashAlg); + exit(1); +} + +static int acvp_mldsa_sigGenPreHash_AFT( + const unsigned char *m, size_t mlen, const unsigned char *context, + size_t ctxlen, const unsigned char rng[MLDSA_RNDBYTES], + const unsigned char sk[CRYPTO_SECRETKEYBYTES], const char *hashAlg) +{ + unsigned char signature[CRYPTO_BYTES]; + size_t siglen; + + if (crypto_sign_signature_pre_hash(signature, &siglen, m, mlen, context, + ctxlen, rng, sk, + str_to_hash_alg(hashAlg)) != 0) + { + return 1; + } + + print_hex("signature", signature, siglen); + return 0; +} + +static int acvp_mldsa_sigVerPreHash_AFT( + const unsigned char *m, size_t mlen, const unsigned char *context, + size_t ctxlen, const unsigned char signature[CRYPTO_BYTES], + const unsigned char pk[CRYPTO_PUBLICKEYBYTES], const char *hashAlg) +{ + return crypto_sign_verify_pre_hash(signature, CRYPTO_BYTES, m, mlen, context, + ctxlen, pk, str_to_hash_alg(hashAlg)); +} + + int main(int argc, char *argv[]) { acvp_mode mode; @@ -280,6 +413,14 @@ int main(int argc, char *argv[]) { mode = sigVerInternal; } + else if (strcmp(*argv, "sigGenPreHash") == 0) + { + mode = sigGenPreHash; + } + else if (strcmp(*argv, "sigVerPreHash") == 0) + { + mode = sigVerPreHash; + } else { goto usage; @@ -514,6 +655,136 @@ int main(int argc, char *argv[]) return acvp_mldsa_sigVerInternal_AFT(message, mlen, signature, pk, externalMu); } + + case sigGenPreHash: + { + unsigned char message[MAX_MSG_LENGTH]; + unsigned char context[MAX_CTX_LENGTH]; + unsigned char rng[MLDSA_RNDBYTES]; + unsigned char sk[CRYPTO_SECRETKEYBYTES]; + char hashAlg[100]; + size_t mlen; + size_t ctxlen; + + /* Parse message */ + if (argc == 0) + { + goto siggen_prehash_usage; + } + mlen = (strlen(*argv) - strlen("message=")) / 2; + if (mlen > MAX_MSG_LENGTH || + decode_hex("message", message, mlen, *argv) != 0) + { + goto siggen_prehash_usage; + } + argc--, argv++; + + /* Parse context */ + if (argc == 0) + { + goto siggen_prehash_usage; + } + ctxlen = (strlen(*argv) - strlen("context=")) / 2; + if (ctxlen > MAX_CTX_LENGTH || + decode_hex("context", context, ctxlen, *argv) != 0) + { + goto siggen_prehash_usage; + } + argc--, argv++; + + /* Parse rng */ + if (argc == 0 || decode_hex("rng", rng, sizeof(rng), *argv) != 0) + { + goto siggen_prehash_usage; + } + argc--, argv++; + + /* Parse sk */ + if (argc == 0 || decode_hex("sk", sk, sizeof(sk), *argv) != 0) + { + goto siggen_prehash_usage; + } + argc--, argv++; + + /* Parse hashAlg */ + if (argc == 0 || + parse_str("hashAlg", hashAlg, sizeof(hashAlg), *argv) != 0) + { + goto siggen_prehash_usage; + } + argc--, argv++; + + /* Call function under test */ + return acvp_mldsa_sigGenPreHash_AFT(message, mlen, context, ctxlen, rng, + sk, hashAlg); + } + + case sigVerPreHash: + { + unsigned char message[MAX_MSG_LENGTH]; + unsigned char context[MAX_CTX_LENGTH]; + unsigned char signature[CRYPTO_BYTES]; + unsigned char pk[CRYPTO_PUBLICKEYBYTES]; + char hashAlg[100]; + size_t mlen; + size_t ctxlen; + + /* Parse message */ + if (argc == 0) + { + goto sigver_prehash_usage; + } + mlen = (strlen(*argv) - strlen("message=")) / 2; + if (mlen > MAX_MSG_LENGTH || + decode_hex("message", message, mlen, *argv) != 0) + { + goto sigver_prehash_usage; + } + argc--, argv++; + + /* Parse context */ + if (argc == 0) + { + goto sigver_prehash_usage; + } + ctxlen = (strlen(*argv) - strlen("context=")) / 2; + if (ctxlen > MAX_CTX_LENGTH || + decode_hex("context", context, ctxlen, *argv) != 0) + { + goto sigver_prehash_usage; + } + argc--, argv++; + + /* Parse signature */ + if (argc == 0 || + decode_hex("signature", signature, sizeof(signature), *argv) != 0) + { + goto sigver_prehash_usage; + } + argc--, argv++; + + + /* Parse pk */ + if (argc == 0 || decode_hex("pk", pk, sizeof(pk), *argv) != 0) + { + goto sigver_prehash_usage; + } + argc--, argv++; + + /* Parse hashAlg */ + if (argc == 0 || + parse_str("hashAlg", hashAlg, sizeof(hashAlg), *argv) != 0) + { + goto sigver_prehash_usage; + } + argc--, argv++; + + + + /* Call function under test */ + return acvp_mldsa_sigVerPreHash_AFT(message, mlen, context, ctxlen, + signature, pk, hashAlg); + } } return (0); @@ -541,4 +812,12 @@ int main(int argc, char *argv[]) sigver_internal_usage: fprintf(stderr, SIGVER_INTERNAL_USAGE "\n"); return (1); + +siggen_prehash_usage: + fprintf(stderr, SIGGEN_PREHASH_USAGE "\n"); + return (1); + +sigver_prehash_usage: + fprintf(stderr, SIGVER_PREHASH_USAGE "\n"); + return (1); } diff --git a/test/mk/components.mk b/test/mk/components.mk index e8cf83b2d..8db9c6c9e 100644 --- a/test/mk/components.mk +++ b/test/mk/components.mk @@ -7,6 +7,7 @@ ifeq ($(OPT),1) FIPS202_SRCS += $(wildcard mldsa/fips202/native/aarch64/src/*.S) $(wildcard mldsa/fips202/native/aarch64/src/*.c) $(wildcard mldsa/fips202/native/x86_64/src/*.c) endif +SHA2_SRCS = $(wildcard mldsa/sha2/*.c) SOURCES += $(wildcard mldsa/*.c) ifeq ($(OPT),1) @@ -20,11 +21,11 @@ MLDSA44_DIR = $(BUILD_DIR)/mldsa44 MLDSA65_DIR = $(BUILD_DIR)/mldsa65 MLDSA87_DIR = $(BUILD_DIR)/mldsa87 -MLDSA44_OBJS = $(call MAKE_OBJS,$(MLDSA44_DIR),$(SOURCES) $(FIPS202_SRCS)) +MLDSA44_OBJS = $(call MAKE_OBJS,$(MLDSA44_DIR),$(SOURCES) $(FIPS202_SRCS) $(SHA2_SRCS)) $(MLDSA44_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=44 -MLDSA65_OBJS = $(call MAKE_OBJS,$(MLDSA65_DIR),$(SOURCES) $(FIPS202_SRCS)) +MLDSA65_OBJS = $(call MAKE_OBJS,$(MLDSA65_DIR),$(SOURCES) $(FIPS202_SRCS) $(SHA2_SRCS)) $(MLDSA65_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=65 -MLDSA87_OBJS = $(call MAKE_OBJS,$(MLDSA87_DIR),$(SOURCES) $(FIPS202_SRCS)) +MLDSA87_OBJS = $(call MAKE_OBJS,$(MLDSA87_DIR),$(SOURCES) $(FIPS202_SRCS) $(SHA2_SRCS)) $(MLDSA87_OBJS): CFLAGS += -DMLD_CONFIG_PARAMETER_SET=87 $(BUILD_DIR)/libmldsa44.a: $(MLDSA44_OBJS)