#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include "../test_helper/test_helper.h"
#include "crypto_api.h"
#include "ssherr.h"
#include "sshkey.h"
#include "sshbuf.h"
#include "log.h"
struct sshbuf *load_text_file(const char *name);
char *get_json_string(struct sshbuf *content, const char *key, int consume);
void mldsa_eddsa_tests(void);
static struct sshbuf *
get_json_b64(struct sshbuf *content, const char *key)
{
char *b64;
struct sshbuf *ret;
b64 = get_json_string(content, key, 0);
ASSERT_PTR_NE(ret = sshbuf_new(), NULL);
ASSERT_INT_EQ(sshbuf_b64tod(ret, b64), 0);
free(b64);
return ret;
}
static void
onerror(void *fuzz)
{
fprintf(stderr, "Failed during fuzz:\n");
fuzz_dump((struct fuzz *)fuzz);
}
static void
sig_fuzz(const uint8_t *m, size_t m_len, const uint8_t *ctx, size_t ctx_len,
const uint8_t *pk, const uint8_t *s)
{
struct fuzz *fuzz;
u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP;
if (test_is_fast())
fuzzers &= ~FUZZ_1_BIT_FLIP;
if (test_is_slow())
fuzzers |= FUZZ_2_BYTE_FLIP;
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(s, m, m_len,
ctx, ctx_len, pk), 0);
fuzz = fuzz_begin(fuzzers, s, MLDSA44_ED25519_SIG_SZ);
TEST_ONERROR(onerror, fuzz);
for(; !fuzz_done(fuzz); fuzz_next(fuzz)) {
if (fuzz_matches_original(fuzz))
continue;
ASSERT_INT_NE(crypto_sign_mldsa44_ed25519_verify(fuzz_ptr(fuzz),
m, m_len, ctx, ctx_len, pk), 0);
}
fuzz_cleanup(fuzz);
}
void
mldsa_eddsa_tests(void)
{
uint8_t pk[MLDSA44_ED25519_PK_SZ];
uint8_t sk[MLDSA44_ED25519_SK_SZ];
uint8_t sig[MLDSA44_ED25519_SIG_SZ];
struct sshbuf *b_m = NULL, *b_ctx = NULL, *b_pk = NULL;
struct sshbuf *b_sk = NULL, *b_s = NULL, *b_sWithContext = NULL;
struct sshbuf *json_buf = NULL;
const uint8_t *tvec_m;
size_t tvec_m_len;
const uint8_t *tvec_ctx;
size_t tvec_ctx_len;
const uint8_t *tvec_pk;
const uint8_t *tvec_sk;
const uint8_t *tvec_s;
const uint8_t *tvec_sWithContext;
TEST_START("MLDSA44-Ed25519-SHA512 load test vectors");
json_buf = load_text_file("draft-ietf-lamps-pq-composite-sigs.json");
b_m = get_json_b64(json_buf, "m");
b_ctx = get_json_b64(json_buf, "ctx");
b_pk = get_json_b64(json_buf, "pk");
b_sk = get_json_b64(json_buf, "sk");
b_s = get_json_b64(json_buf, "s");
b_sWithContext = get_json_b64(json_buf, "sWithContext");
ASSERT_INT_EQ(sshbuf_len(b_pk), MLDSA44_ED25519_PK_SZ);
ASSERT_INT_EQ(sshbuf_len(b_sk), MLDSA44_ED25519_SK_SZ);
ASSERT_INT_EQ(sshbuf_len(b_s), MLDSA44_ED25519_SIG_SZ);
ASSERT_INT_EQ(sshbuf_len(b_sWithContext), MLDSA44_ED25519_SIG_SZ);
TEST_DONE();
tvec_m = sshbuf_ptr(b_m);
tvec_m_len = sshbuf_len(b_m);
tvec_ctx = sshbuf_ptr(b_ctx);
tvec_ctx_len = sshbuf_len(b_ctx);
tvec_pk = sshbuf_ptr(b_pk);
tvec_sk = sshbuf_ptr(b_sk);
tvec_s = sshbuf_ptr(b_s);
tvec_sWithContext = sshbuf_ptr(b_sWithContext);
TEST_START("MLDSA44-Ed25519-SHA512 raw self-consistency");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_keygen(pk, sk), 0);
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_sign(sig,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, sk), 0);
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(sig,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, pk), 0);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 raw KAT key expansion");
uint8_t pk_expanded[MLDSA44_ED25519_PK_SZ];
uint8_t sk_expanded[MLDSA44_ED25519_SK_SZ];
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_keygen_seeded(pk_expanded,
sk_expanded, tvec_sk, tvec_sk + 32), 0);
ASSERT_MEM_EQ(pk_expanded, tvec_pk, MLDSA44_ED25519_PK_SZ);
ASSERT_MEM_EQ(sk_expanded, tvec_sk, MLDSA44_ED25519_SK_SZ);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 raw KAT verify (no context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(tvec_s, tvec_m,
tvec_m_len, NULL, 0, tvec_pk), 0);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 raw KAT verify (with context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(tvec_sWithContext,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, tvec_pk), 0);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 raw round-trip (no context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_sign(sig, tvec_m, tvec_m_len,
NULL, 0, tvec_sk), 0);
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(sig,
tvec_m, tvec_m_len, NULL, 0, tvec_pk), 0);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 raw round-trip (with context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_sign(sig,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, tvec_sk), 0);
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(sig,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, tvec_pk), 0);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 raw KAT verify (no context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(tvec_s, tvec_m,
tvec_m_len, NULL, 0, tvec_pk), 0);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 fuzz raw verify (with context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(tvec_sWithContext,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, tvec_pk), 0);
sig_fuzz(tvec_m, tvec_m_len, NULL, 0, tvec_pk, tvec_s);
TEST_DONE();
TEST_START("MLDSA44-Ed25519-SHA512 fuzz raw verify (with context)");
ASSERT_INT_EQ(crypto_sign_mldsa44_ed25519_verify(tvec_sWithContext,
tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len, tvec_pk), 0);
sig_fuzz(tvec_m, tvec_m_len, tvec_ctx, tvec_ctx_len,
tvec_pk, tvec_sWithContext);
TEST_DONE();
sshbuf_free(json_buf);
sshbuf_free(b_m);
sshbuf_free(b_ctx);
sshbuf_free(b_pk);
sshbuf_free(b_sk);
sshbuf_free(b_s);
sshbuf_free(b_sWithContext);
}