diff --git a/sdk/software/examples/mlkem_test/main.c b/sdk/software/examples/mlkem_test/main.c index c8e1908..45951ef 100644 --- a/sdk/software/examples/mlkem_test/main.c +++ b/sdk/software/examples/mlkem_test/main.c @@ -20,6 +20,8 @@ #include #include +#include + #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;