zupt/jasmin/zupt_aes_ctr.jazz
Cristian Cezar Moisés 06c877ec86 feat: add Jasmin assembly integration for crypto acceleration
- Integrated `zupt_mac_verify_ct` in `zupt_decrypt_buffer()` to replace C XOR loop for HMAC-SHA256
- Integrated `zupt_ct_select_32` in `zupt_mlkem768_decaps()` to replace C `cmov()` for FO transformation
- Added `include/zupt_jasmin.h` with extern declarations and ABI docs
- Added `#ifdef ZUPT_USE_JASMIN` guards with clean C fallbacks in `zupt_crypto.c` and `zupt_mlkem.c`
- Makefile now auto-detects `jasmin/*.s`, assembles and links with `-DZUPT_USE_JASMIN`

Closes #3
2026-03-28 23:03:04 -03:00

124 lines
3 KiB
Text

/* Zupt — AES-256 Single Block Encrypt via AES-NI (Jasmin)
* Copyright (c) 2026 Cristian Cezar Moisés — MIT License
*
* CT-REQUIRED: AES-NI has no data-dependent timing.
*
* Uses reg ptr for read-only u128 inputs (key, counter, plaintext).
* Uses reg u64 for write output (store infers width from reg u128 source).
* C handles CTR loop and tail bytes.
*/
inline fn key_expand_even(reg u128 t0, reg u128 assist) -> reg u128 {
reg u128 tmp;
assist = #VPSHUFD(assist, 0xFF);
tmp = #VPSLLDQ(t0, 4);
t0 ^= tmp;
tmp = #VPSLLDQ(t0, 4);
t0 ^= tmp;
tmp = #VPSLLDQ(t0, 4);
t0 ^= tmp;
t0 ^= assist;
return t0;
}
inline fn key_expand_odd(reg u128 t0, reg u128 t1) -> reg u128 {
reg u128 tmp assist;
assist = #VAESKEYGENASSIST(t0, 0);
assist = #VPSHUFD(assist, 0xAA);
tmp = #VPSLLDQ(t1, 4);
t1 ^= tmp;
tmp = #VPSLLDQ(t1, 4);
t1 ^= tmp;
tmp = #VPSLLDQ(t1, 4);
t1 ^= tmp;
t1 ^= assist;
return t1;
}
export fn zupt_aes256_blk(
reg u64 out_ptr,
reg ptr u128[1] in_blk,
reg ptr u128[2] key,
reg ptr u128[1] ctr_blk)
{
stack u128[15] rk;
reg u128 t0 t1 assist b data;
/* Key expansion */
t0 = key.[0];
t1 = key.[1];
rk.[0] = t0;
rk.[1] = t1;
assist = #VAESKEYGENASSIST(t1, 0x01);
t0 = key_expand_even(t0, assist);
rk.[2] = t0;
t1 = key_expand_odd(t0, t1);
rk.[3] = t1;
assist = #VAESKEYGENASSIST(t1, 0x02);
t0 = key_expand_even(t0, assist);
rk.[4] = t0;
t1 = key_expand_odd(t0, t1);
rk.[5] = t1;
assist = #VAESKEYGENASSIST(t1, 0x04);
t0 = key_expand_even(t0, assist);
rk.[6] = t0;
t1 = key_expand_odd(t0, t1);
rk.[7] = t1;
assist = #VAESKEYGENASSIST(t1, 0x08);
t0 = key_expand_even(t0, assist);
rk.[8] = t0;
t1 = key_expand_odd(t0, t1);
rk.[9] = t1;
assist = #VAESKEYGENASSIST(t1, 0x10);
t0 = key_expand_even(t0, assist);
rk.[10] = t0;
t1 = key_expand_odd(t0, t1);
rk.[11] = t1;
assist = #VAESKEYGENASSIST(t1, 0x20);
t0 = key_expand_even(t0, assist);
rk.[12] = t0;
t1 = key_expand_odd(t0, t1);
rk.[13] = t1;
assist = #VAESKEYGENASSIST(t1, 0x40);
t0 = key_expand_even(t0, assist);
rk.[14] = t0;
/* Encrypt counter block: 14 rounds AES-256 */
b = ctr_blk.[0];
b ^= rk.[0];
b = #VAESENC(b, rk.[1]);
b = #VAESENC(b, rk.[2]);
b = #VAESENC(b, rk.[3]);
b = #VAESENC(b, rk.[4]);
b = #VAESENC(b, rk.[5]);
b = #VAESENC(b, rk.[6]);
b = #VAESENC(b, rk.[7]);
b = #VAESENC(b, rk.[8]);
b = #VAESENC(b, rk.[9]);
b = #VAESENC(b, rk.[10]);
b = #VAESENC(b, rk.[11]);
b = #VAESENC(b, rk.[12]);
b = #VAESENC(b, rk.[13]);
b = #VAESENCLAST(b, rk.[14]);
/* XOR keystream with plaintext, store result */
data = in_blk.[0];
b ^= data;
[out_ptr + 0] = b;
/* Wipe round keys */
reg u128 wipe;
inline int z;
for z = 0 to 15 {
wipe = rk.[z];
wipe ^= wipe;
rk.[z] = wipe;
}
}