Add MLKEM DMA comparison test
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <confreg_time.h>
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
/* ─── BSP globals ─────────────────────────────────────────────────── */
|
||||
@@ -189,6 +191,13 @@ static void clear_uc(volatile uint8_t *b, int n)
|
||||
b[i] = 0;
|
||||
}
|
||||
|
||||
static void copy_from_uc(uint8_t *dst, volatile uint8_t *src, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
/* Arbitrary but fixed test seeds / message (32 bytes each). */
|
||||
static uint8_t SEED_D[32] = {
|
||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
|
||||
@@ -203,11 +212,16 @@ static uint8_t MSG_M[32] = {
|
||||
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF
|
||||
};
|
||||
|
||||
static uint8_t ek[EK_BYTES] __attribute__((aligned(64)));
|
||||
static uint8_t dk[DK_BYTES] __attribute__((aligned(64)));
|
||||
static uint8_t ct[CT_BYTES] __attribute__((aligned(64)));
|
||||
static uint8_t ss_enc[32];
|
||||
static uint8_t ss_dec[32];
|
||||
typedef struct {
|
||||
uint8_t ek[EK_BYTES] __attribute__((aligned(64)));
|
||||
uint8_t dk[DK_BYTES] __attribute__((aligned(64)));
|
||||
uint8_t ct[CT_BYTES] __attribute__((aligned(64)));
|
||||
uint8_t ss_enc[32];
|
||||
uint8_t ss_dec[32];
|
||||
} mlkem_result_t;
|
||||
|
||||
static mlkem_result_t cpu_res;
|
||||
static mlkem_result_t dma_res;
|
||||
|
||||
static void print_hex(const char *label, const uint8_t *b, int n)
|
||||
{
|
||||
@@ -218,92 +232,147 @@ static void print_hex(const char *label, const uint8_t *b, int n)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
static int verify_result(const mlkem_result_t *res)
|
||||
{
|
||||
int i, mismatch;
|
||||
volatile uint8_t *ek_uc = uncached_u8(ek);
|
||||
volatile uint8_t *dk_uc = uncached_u8(dk);
|
||||
volatile uint8_t *ct_uc = uncached_u8(ct);
|
||||
mismatch = 0;
|
||||
for (i = 0; i < 32; i++)
|
||||
if (res->ss_enc[i] != res->ss_dec[i]) mismatch++;
|
||||
|
||||
return mismatch;
|
||||
}
|
||||
|
||||
static void clear_result_cpu(mlkem_result_t *res)
|
||||
{
|
||||
memset(res, 0, sizeof(*res));
|
||||
}
|
||||
|
||||
static void clear_result_dma(mlkem_result_t *res)
|
||||
{
|
||||
volatile uint8_t *p = (volatile uint8_t *)UNCACHED_ADDR(res);
|
||||
clear_uc(p, sizeof(*res));
|
||||
}
|
||||
|
||||
static unsigned long run_roundtrip_cpu(const uint8_t *seed_d,
|
||||
const uint8_t *seed_z,
|
||||
const uint8_t *msg,
|
||||
mlkem_result_t *res)
|
||||
{
|
||||
unsigned long t0, t1;
|
||||
|
||||
clear_result_cpu(res);
|
||||
t0 = get_clock_count();
|
||||
|
||||
write_block32(MLKEM_D, seed_d);
|
||||
write_block32(MLKEM_Z, seed_z);
|
||||
run_op(OP_KEYGEN);
|
||||
readback(RDB_EK, res->ek, EK_BYTES);
|
||||
readback(RDB_DK, res->dk, DK_BYTES);
|
||||
|
||||
preload(PRE_EK, res->ek, EK_BYTES);
|
||||
write_block32(MLKEM_MSG, msg);
|
||||
run_op(OP_ENCAPS);
|
||||
read_block32(MLKEM_SS, res->ss_enc);
|
||||
readback(RDB_CT, res->ct, CT_BYTES);
|
||||
|
||||
preload(PRE_DK, res->dk, DK_BYTES);
|
||||
preload(PRE_C, res->ct, CT_BYTES);
|
||||
run_op(OP_DECAPS);
|
||||
read_block32(MLKEM_SS, res->ss_dec);
|
||||
|
||||
t1 = get_clock_count();
|
||||
return t1 - t0;
|
||||
}
|
||||
|
||||
static unsigned long run_roundtrip_dma(const uint8_t *seed_d,
|
||||
const uint8_t *seed_z,
|
||||
const uint8_t *msg,
|
||||
mlkem_result_t *res)
|
||||
{
|
||||
unsigned long t0, t1;
|
||||
volatile uint8_t *ek_uc = uncached_u8(res->ek);
|
||||
volatile uint8_t *dk_uc = uncached_u8(res->dk);
|
||||
volatile uint8_t *ct_uc = uncached_u8(res->ct);
|
||||
|
||||
clear_result_dma(res);
|
||||
t0 = get_clock_count();
|
||||
|
||||
write_block32(MLKEM_D, seed_d);
|
||||
write_block32(MLKEM_Z, seed_z);
|
||||
run_op(OP_KEYGEN);
|
||||
dma_from_mlkem(ek_uc, MLKEM_EK_WINDOW, EK_BYTES);
|
||||
dma_from_mlkem(dk_uc, MLKEM_DK_WINDOW, DK_BYTES);
|
||||
|
||||
dma_to_mlkem(MLKEM_EK_WINDOW, ek_uc, EK_BYTES);
|
||||
write_block32(MLKEM_MSG, msg);
|
||||
run_op(OP_ENCAPS);
|
||||
read_block32(MLKEM_SS, res->ss_enc);
|
||||
dma_from_mlkem(ct_uc, MLKEM_CT_WINDOW, CT_BYTES);
|
||||
|
||||
dma_to_mlkem(MLKEM_DK_WINDOW, dk_uc, DK_BYTES);
|
||||
dma_to_mlkem(MLKEM_CT_WINDOW, ct_uc, CT_BYTES);
|
||||
run_op(OP_DECAPS);
|
||||
read_block32(MLKEM_SS, res->ss_dec);
|
||||
|
||||
t1 = get_clock_count();
|
||||
|
||||
copy_from_uc(res->ek, ek_uc, EK_BYTES);
|
||||
copy_from_uc(res->dk, dk_uc, DK_BYTES);
|
||||
copy_from_uc(res->ct, ct_uc, CT_BYTES);
|
||||
|
||||
return t1 - t0;
|
||||
}
|
||||
|
||||
static int compare_results(const mlkem_result_t *a, const mlkem_result_t *b)
|
||||
{
|
||||
return memcmp(a->ek, b->ek, EK_BYTES) ||
|
||||
memcmp(a->dk, b->dk, DK_BYTES) ||
|
||||
memcmp(a->ct, b->ct, CT_BYTES) ||
|
||||
memcmp(a->ss_enc, b->ss_enc, sizeof(a->ss_enc)) ||
|
||||
memcmp(a->ss_dec, b->ss_dec, sizeof(a->ss_dec));
|
||||
}
|
||||
|
||||
static unsigned long cycles_to_us(unsigned long cycles)
|
||||
{
|
||||
return cycles / (CORE_CLOCKS_PER_SEC / USEC_PER_SEC);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int mismatch_cpu, mismatch_dma, result_diff;
|
||||
unsigned long cpu_cycles, dma_cycles;
|
||||
|
||||
printf("MLKEM_START\n");
|
||||
|
||||
/* ── 1. KeyGen: d,z -> ek, dk ─────────────────────────────────── */
|
||||
write_block32(MLKEM_D, SEED_D);
|
||||
write_block32(MLKEM_Z, SEED_Z);
|
||||
run_op(OP_KEYGEN);
|
||||
dma_from_mlkem(ek_uc, MLKEM_EK_WINDOW, EK_BYTES);
|
||||
dma_from_mlkem(dk_uc, MLKEM_DK_WINDOW, DK_BYTES);
|
||||
print_hex_uc("EK32=", ek_uc, 32); /* first 32 bytes as a fingerprint */
|
||||
cpu_cycles = run_roundtrip_cpu(SEED_D, SEED_Z, MSG_M, &cpu_res);
|
||||
dma_cycles = run_roundtrip_dma(SEED_D, SEED_Z, MSG_M, &dma_res);
|
||||
|
||||
/* ── 2. Encaps: ek + msg -> ss, ct ────────────────────────────── */
|
||||
dma_to_mlkem(MLKEM_EK_WINDOW, ek_uc, EK_BYTES);
|
||||
write_block32(MLKEM_MSG, MSG_M);
|
||||
run_op(OP_ENCAPS);
|
||||
read_block32(MLKEM_SS, ss_enc);
|
||||
dma_from_mlkem(ct_uc, MLKEM_CT_WINDOW, CT_BYTES);
|
||||
print_hex("SS_ENC=", ss_enc, 32);
|
||||
mismatch_cpu = verify_result(&cpu_res);
|
||||
mismatch_dma = verify_result(&dma_res);
|
||||
result_diff = compare_results(&cpu_res, &dma_res);
|
||||
|
||||
/* ── 3. Decaps: dk + ct -> ss' ────────────────────────────────── */
|
||||
dma_to_mlkem(MLKEM_DK_WINDOW, dk_uc, DK_BYTES);
|
||||
dma_to_mlkem(MLKEM_CT_WINDOW, ct_uc, CT_BYTES);
|
||||
run_op(OP_DECAPS);
|
||||
read_block32(MLKEM_SS, ss_dec);
|
||||
print_hex("SS_DEC=", ss_dec, 32);
|
||||
print_hex("CPU_EK32=", cpu_res.ek, 32);
|
||||
print_hex("CPU_SS_ENC=", cpu_res.ss_enc, 32);
|
||||
print_hex("CPU_SS_DEC=", cpu_res.ss_dec, 32);
|
||||
print_hex("DMA_EK32=", dma_res.ek, 32);
|
||||
print_hex("DMA_SS_ENC=", dma_res.ss_enc, 32);
|
||||
print_hex("DMA_SS_DEC=", dma_res.ss_dec, 32);
|
||||
|
||||
/* ── 4. Verify shared secrets match ───────────────────────────── */
|
||||
mismatch = 0;
|
||||
for (i = 0; i < 32; i++)
|
||||
if (ss_enc[i] != ss_dec[i]) mismatch++;
|
||||
printf("MLKEM_CPU_CYCLES=%lu\n", cpu_cycles);
|
||||
printf("MLKEM_DMA_CYCLES=%lu\n", dma_cycles);
|
||||
printf("MLKEM_CPU_US=%lu\n", cycles_to_us(cpu_cycles));
|
||||
printf("MLKEM_DMA_US=%lu\n", cycles_to_us(dma_cycles));
|
||||
if (dma_cycles != 0) {
|
||||
unsigned long speedup_x100 = (cpu_cycles * 100u) / dma_cycles;
|
||||
printf("MLKEM_DMA_SPEEDUP_X100=%lu\n", speedup_x100);
|
||||
}
|
||||
|
||||
if (mismatch == 0)
|
||||
if (mismatch_cpu == 0 && mismatch_dma == 0 && result_diff == 0)
|
||||
printf("MLKEM_RESULT=PASS\n");
|
||||
else
|
||||
printf("MLKEM_RESULT=FAIL (%d byte mismatch)\n", mismatch);
|
||||
|
||||
printf("MLKEM_DONE\n");
|
||||
|
||||
|
||||
SEED_D[2] = 0;
|
||||
SEED_Z[2] = 0;
|
||||
MSG_M[2] = 0;
|
||||
clear_uc(ek_uc, sizeof(ek));
|
||||
clear_uc(dk_uc, sizeof(dk));
|
||||
clear_uc(ct_uc, sizeof(ct));
|
||||
memset(ss_enc, 0, sizeof(ss_enc));
|
||||
memset(ss_dec, 0, sizeof(ss_dec));
|
||||
|
||||
/* ── 1. KeyGen: d,z -> ek, dk ─────────────────────────────────── */
|
||||
write_block32(MLKEM_D, SEED_D);
|
||||
write_block32(MLKEM_Z, SEED_Z);
|
||||
run_op(OP_KEYGEN);
|
||||
dma_from_mlkem(ek_uc, MLKEM_EK_WINDOW, EK_BYTES);
|
||||
dma_from_mlkem(dk_uc, MLKEM_DK_WINDOW, DK_BYTES);
|
||||
print_hex_uc("EK32=", ek_uc, 32); /* first 32 bytes as a fingerprint */
|
||||
|
||||
/* ── 2. Encaps: ek + msg -> ss, ct ────────────────────────────── */
|
||||
dma_to_mlkem(MLKEM_EK_WINDOW, ek_uc, EK_BYTES);
|
||||
write_block32(MLKEM_MSG, MSG_M);
|
||||
run_op(OP_ENCAPS);
|
||||
read_block32(MLKEM_SS, ss_enc);
|
||||
dma_from_mlkem(ct_uc, MLKEM_CT_WINDOW, CT_BYTES);
|
||||
print_hex("SS_ENC=", ss_enc, 32);
|
||||
|
||||
/* ── 3. Decaps: dk + ct -> ss' ────────────────────────────────── */
|
||||
dma_to_mlkem(MLKEM_DK_WINDOW, dk_uc, DK_BYTES);
|
||||
dma_to_mlkem(MLKEM_CT_WINDOW, ct_uc, CT_BYTES);
|
||||
run_op(OP_DECAPS);
|
||||
read_block32(MLKEM_SS, ss_dec);
|
||||
print_hex("SS_DEC=", ss_dec, 32);
|
||||
|
||||
/* ── 4. Verify shared secrets match ───────────────────────────── */
|
||||
mismatch = 0;
|
||||
for (i = 0; i < 32; i++)
|
||||
if (ss_enc[i] != ss_dec[i]) mismatch++;
|
||||
|
||||
if (mismatch == 0)
|
||||
printf("MLKEM_RESULT=PASS\n");
|
||||
else
|
||||
printf("MLKEM_RESULT=FAIL (%d byte mismatch)\n", mismatch);
|
||||
else {
|
||||
printf("MLKEM_RESULT=FAIL cpu_mismatch=%d dma_mismatch=%d result_diff=%d\n",
|
||||
mismatch_cpu, mismatch_dma, result_diff);
|
||||
}
|
||||
|
||||
printf("MLKEM_DONE\n");
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user