ab_riscv_interpreter/rv32/zk/zkn/zkne/
rv32_zkne_helpers.rs1use ab_riscv_primitives::prelude::*;
4use const_fn_specialization::const_fn_specialization;
5
6#[expect(
11 clippy::inline_modules,
12 reason = "Small internal API, it is more readable this way"
13)]
14pub(in super::super) mod soft {
15 use crate::rv32::zk::zkn::zknd::rv32_zknd_helpers::{SBOX, gmul};
16
17 #[inline(always)]
31 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
32 pub(super) const fn mix_col_byte(b: u8) -> u32 {
33 let r0 = u32::from(gmul(b, 0x02));
34 let r1 = u32::from(b);
35 let r2 = u32::from(b);
36 let r3 = u32::from(gmul(b, 0x03));
37 r0 | (r1 << 8) | (r2 << 16) | (r3 << 24)
38 }
39
40 #[inline(always)]
50 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
51 pub(super) const fn aes32esi(rs1: u32, rs2: u32, bs: u8) -> u32 {
52 let shamt = u32::from(bs) * 8;
53 let si = ((rs2 >> shamt) & 0xff) as u8;
54 let so = u32::from(SBOX[usize::from(si)]);
55 rs1 ^ so.rotate_left(shamt)
56 }
57
58 #[inline(always)]
69 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
70 pub(super) const fn aes32esmi(rs1: u32, rs2: u32, bs: u8) -> u32 {
71 let shamt = u32::from(bs) * 8;
72 let si = ((rs2 >> shamt) & 0xff) as u8;
73 let so = SBOX[usize::from(si)];
74 let mixed = mix_col_byte(so);
75 rs1 ^ mixed.rotate_left(shamt)
76 }
77}
78
79#[const_fn_specialization]
80#[inline(always)]
81#[doc(hidden)]
82#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
83pub fn aes32esi(rs1: u32, rs2: u32, bs: Rv32AesBs) -> u32 {
84 cfg_select! {
86 all(not(miri), target_arch = "riscv32", target_feature = "zkne") => {
87 unsafe {
89 match bs {
91 Rv32AesBs::B0 => core::arch::riscv32::aes32esi::<0>(rs1, rs2),
92 Rv32AesBs::B1 => core::arch::riscv32::aes32esi::<1>(rs1, rs2),
93 Rv32AesBs::B2 => core::arch::riscv32::aes32esi::<2>(rs1, rs2),
94 Rv32AesBs::B3 => core::arch::riscv32::aes32esi::<3>(rs1, rs2),
95 }
96 }
97 }
98 _ => soft::aes32esi(rs1, rs2, u8::from(bs)),
99 }
100}
101
102#[const_fn_specialization]
103#[inline(always)]
104#[doc(hidden)]
105#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
106pub fn aes32esmi(rs1: u32, rs2: u32, bs: Rv32AesBs) -> u32 {
107 cfg_select! {
109 all(not(miri), target_arch = "riscv32", target_feature = "zkne") => {
110 unsafe {
112 match bs {
114 Rv32AesBs::B0 => core::arch::riscv32::aes32esmi::<0>(rs1, rs2),
115 Rv32AesBs::B1 => core::arch::riscv32::aes32esmi::<1>(rs1, rs2),
116 Rv32AesBs::B2 => core::arch::riscv32::aes32esmi::<2>(rs1, rs2),
117 Rv32AesBs::B3 => core::arch::riscv32::aes32esmi::<3>(rs1, rs2),
118 }
119 }
120 }
121 _ => soft::aes32esmi(rs1, rs2, u8::from(bs)),
122 }
123}
124
125#[const_fn_specialization]
126#[inline(always)]
127#[doc(hidden)]
128#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
129pub const fn aes32esi(rs1: u32, rs2: u32, bs: Rv32AesBs) -> u32 {
130 soft::aes32esi(rs1, rs2, bs as u8)
131}
132
133#[const_fn_specialization]
134#[inline(always)]
135#[doc(hidden)]
136#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
137pub const fn aes32esmi(rs1: u32, rs2: u32, bs: Rv32AesBs) -> u32 {
138 soft::aes32esmi(rs1, rs2, bs as u8)
139}