ab_riscv_interpreter/rv64/zk/zkn/zknd/
rv64_zknd_helpers.rs1use ab_riscv_primitives::prelude::*;
4
5#[cfg(not(all(not(miri), target_arch = "riscv64", target_feature = "zknd")))]
9#[expect(
10 clippy::inline_modules,
11 reason = "Small internal API, it is more readable this way"
12)]
13mod ks {
14 use crate::rv32::zk::zkn::zknd::rv32_zknd_helpers::SBOX;
15 use ab_riscv_primitives::prelude::*;
16
17 #[inline(always)]
28 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
29 pub(super) fn aes64ks1i(rs1: u64, rnum: Rv64ZkndKsRnum) -> u64 {
30 let w = (rs1 >> 32u8) as u32;
31
32 let rotated = if rnum == Rv64ZkndKsRnum::Final {
33 w
34 } else {
35 w.rotate_right(8)
36 };
37
38 let b0 = u32::from(SBOX[(rotated & 0xff) as usize]);
39 let b1 = u32::from(SBOX[((rotated >> 8u8) & 0xff) as usize]);
40 let b2 = u32::from(SBOX[((rotated >> 16u8) & 0xff) as usize]);
41 let b3 = u32::from(SBOX[((rotated >> 24u8) & 0xff) as usize]);
42 let subbed = b0 | (b1 << 8u8) | (b2 << 16u8) | (b3 << 24u8);
43
44 let result = if let Some(round_constant) = rnum.constant() {
45 subbed ^ u32::from(round_constant)
46 } else {
47 subbed
48 };
49
50 u64::from(result) | (u64::from(result) << 32u8)
51 }
52
53 #[inline(always)]
62 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
63 pub(super) fn aes64ks2(rs1: u64, rs2: u64) -> u64 {
64 let w0 = (rs1 >> 32u8) as u32 ^ rs2 as u32;
65 let w1 = w0 ^ (rs2 >> 32u8) as u32;
66 u64::from(w0) | (u64::from(w1) << 32u8)
67 }
68}
69
70cfg_select! {
71 all(
72 not(miri),
73 target_arch = "riscv64",
74 target_feature = "zknd"
75 ) => {
76 }
78 all(target_arch = "x86_64", target_feature = "aes", target_feature = "sse4.1") => {
79 #[expect(
81 clippy::inline_modules,
82 reason = "Small internal API, it is more readable this way"
83 )]
84 mod x86_64 {
85 use core::arch::x86_64::{
86 _mm_aesdec_si128, _mm_aesdeclast_si128, _mm_aesimc_si128, _mm_extract_epi64,
87 _mm_set_epi64x, _mm_setzero_si128,
88 };
89
90 #[inline]
93 #[target_feature(enable = "aes,sse4.1")]
94 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
95 pub(super) fn aes64ds(rs1: u64, rs2: u64) -> u64 {
96 let state = _mm_set_epi64x(rs2.cast_signed(), rs1.cast_signed());
97 let zero = _mm_setzero_si128();
98 let result = _mm_aesdeclast_si128(state, zero);
99 _mm_extract_epi64::<0>(result).cast_unsigned()
100 }
101
102 #[inline]
105 #[target_feature(enable = "aes,sse4.1")]
106 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
107 pub(super) fn aes64dsm(rs1: u64, rs2: u64) -> u64 {
108 let state = _mm_set_epi64x(rs2.cast_signed(), rs1.cast_signed());
109 let zero = _mm_setzero_si128();
110 let result = _mm_aesdec_si128(state, zero);
111 _mm_extract_epi64::<0>(result).cast_unsigned()
112 }
113
114 #[inline]
117 #[target_feature(enable = "aes,sse4.1")]
118 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
119 pub(super) fn aes64im(rs1: u64) -> u64 {
120 let state = _mm_set_epi64x(rs1.cast_signed(), rs1.cast_signed());
121 let result = _mm_aesimc_si128(state);
122 _mm_extract_epi64::<0>(result).cast_unsigned()
123 }
124 }
125 }
126 all(target_arch = "aarch64", target_feature = "aes") => {
127 #[expect(
129 clippy::inline_modules,
130 reason = "Small internal API, it is more readable this way"
131 )]
132 mod aarch64 {
133 use core::arch::aarch64::{
134 vaesdq_u8, vaesimcq_u8, vcombine_u64, vcreate_u64, vdupq_n_u8, vgetq_lane_u64,
135 vreinterpretq_u8_u64, vreinterpretq_u64_u8,
136 };
137
138 #[inline]
142 #[target_feature(enable = "aes")]
143 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
144 pub(super) fn aes64ds(rs1: u64, rs2: u64) -> u64 {
145 let state = vreinterpretq_u8_u64(vcombine_u64(vcreate_u64(rs1), vcreate_u64(rs2)));
146 let zero = vdupq_n_u8(0);
147 let result = vaesdq_u8(state, zero);
148 vgetq_lane_u64::<0>(vreinterpretq_u64_u8(result))
149 }
150
151 #[inline]
153 #[target_feature(enable = "aes")]
154 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
155 pub(super) fn aes64dsm(rs1: u64, rs2: u64) -> u64 {
156 let state = vreinterpretq_u8_u64(vcombine_u64(vcreate_u64(rs1), vcreate_u64(rs2)));
157 let zero = vdupq_n_u8(0);
158 let after_sub_shift = vaesdq_u8(state, zero);
159 let result = vaesimcq_u8(after_sub_shift);
160 vgetq_lane_u64::<0>(vreinterpretq_u64_u8(result))
161 }
162
163 #[inline]
164 #[target_feature(enable = "aes")]
165 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
166 pub(super) fn aes64im(rs1: u64) -> u64 {
167 let state = vreinterpretq_u8_u64(vcombine_u64(vcreate_u64(rs1), vcreate_u64(rs1)));
168 let result = vaesimcq_u8(state);
169 vgetq_lane_u64::<0>(vreinterpretq_u64_u8(result))
170 }
171 }
172 }
173 _ => {
174 #[expect(
176 clippy::inline_modules,
177 reason = "Small internal API, it is more readable this way"
178 )]
179 mod soft {
180 use crate::rv32::zk::zkn::zknd::rv32_zknd_helpers::{INV_SBOX, gmul};
181
182 #[inline(always)]
183 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
184 fn inv_mix_col(col: u32) -> u32 {
185 let s0 = col as u8;
186 let s1 = (col >> 8u8) as u8;
187 let s2 = (col >> 16u8) as u8;
188 let s3 = (col >> 24u8) as u8;
189 let r0 = gmul(s0, 0x0e) ^ gmul(s1, 0x0b) ^ gmul(s2, 0x0d) ^ gmul(s3, 0x09);
190 let r1 = gmul(s0, 0x09) ^ gmul(s1, 0x0e) ^ gmul(s2, 0x0b) ^ gmul(s3, 0x0d);
191 let r2 = gmul(s0, 0x0d) ^ gmul(s1, 0x09) ^ gmul(s2, 0x0e) ^ gmul(s3, 0x0b);
192 let r3 = gmul(s0, 0x0b) ^ gmul(s1, 0x0d) ^ gmul(s2, 0x09) ^ gmul(s3, 0x0e);
193 u32::from(r0) | (u32::from(r1) << 8u8) | (u32::from(r2) << 16u8) | (u32::from(r3) << 24u8)
194 }
195
196 #[inline(always)]
206 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
207 pub(super) fn aes64ds(rs1: u64, rs2: u64) -> u64 {
208 let state_byte = |col: usize, row: usize| -> u8 {
209 let word = if col < 2 { rs1 } else { rs2 };
210 (word >> ((col % 2) * 32 + row * 8)) as u8
211 };
212
213 let mut out = 0;
214 for c in 0..2usize {
215 for r in 0..4usize {
216 let src_col = (c + 4 - r) & 3;
217 let b = INV_SBOX[state_byte(src_col, r) as usize];
218 out |= u64::from(b) << (c * 32 + r * 8);
219 }
220 }
221 out
222 }
223
224 #[inline(always)]
225 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
226 pub(super) fn aes64dsm(rs1: u64, rs2: u64) -> u64 {
227 let lo = aes64ds(rs1, rs2);
228 let col0 = inv_mix_col(lo as u32);
229 let col1 = inv_mix_col((lo >> 32u8) as u32);
230 u64::from(col0) | (u64::from(col1) << 32u8)
231 }
232
233 #[inline(always)]
234 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
235 pub(super) fn aes64im(rs1: u64) -> u64 {
236 let col0 = inv_mix_col(rs1 as u32);
237 let col1 = inv_mix_col((rs1 >> 32u8) as u32);
238 u64::from(col0) | (u64::from(col1) << 32u8)
239 }
240 }
241 }
242}
243
244#[inline(always)]
245#[doc(hidden)]
246#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
247pub fn aes64ds(rs1: u64, rs2: u64) -> u64 {
248 cfg_select! {
250 all(
251 not(miri),
252 target_arch = "riscv64",
253 target_feature = "zknd"
254 ) => {
255 unsafe {
257 core::arch::riscv64::aes64ds(rs1, rs2)
258 }
259 }
260 all(target_arch = "x86_64", target_feature = "aes", target_feature = "sse4.1") => {
261 unsafe {
263 x86_64::aes64ds(rs1, rs2)
264 }
265 }
266 all(target_arch = "aarch64", target_feature = "aes") => {
267 unsafe {
269 aarch64::aes64ds(rs1, rs2)
270 }
271 }
272 _ => { soft::aes64ds(rs1, rs2) }
273 }
274}
275
276#[inline(always)]
277#[doc(hidden)]
278#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
279pub fn aes64dsm(rs1: u64, rs2: u64) -> u64 {
280 cfg_select! {
282 all(
283 not(miri),
284 target_arch = "riscv64",
285 target_feature = "zknd"
286 ) => {
287 unsafe {
289 core::arch::riscv64::aes64dsm(rs1, rs2)
290 }
291 }
292 all(target_arch = "x86_64", target_feature = "aes", target_feature = "sse4.1") => {
293 unsafe {
295 x86_64::aes64dsm(rs1, rs2)
296 }
297 }
298 all(target_arch = "aarch64", target_feature = "aes") => {
299 unsafe {
301 aarch64::aes64dsm(rs1, rs2)
302 }
303 }
304 _ => { soft::aes64dsm(rs1, rs2) }
305 }
306}
307
308#[inline(always)]
309#[doc(hidden)]
310#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
311pub fn aes64im(rs1: u64) -> u64 {
312 cfg_select! {
314 all(
315 not(miri),
316 target_arch = "riscv64",
317 target_feature = "zknd"
318 ) => {
319 unsafe {
321 core::arch::riscv64::aes64im(rs1)
322 }
323 }
324 all(target_arch = "x86_64", target_feature = "aes", target_feature = "sse4.1") => {
325 unsafe {
327 x86_64::aes64im(rs1)
328 }
329 }
330 all(target_arch = "aarch64", target_feature = "aes") => {
331 unsafe {
333 aarch64::aes64im(rs1)
334 }
335 }
336 _ => { soft::aes64im(rs1) }
337 }
338}
339
340#[inline(always)]
341#[doc(hidden)]
342#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
343pub fn aes64ks1i(rs1: u64, rnum: Rv64ZkndKsRnum) -> u64 {
344 cfg_select! {
346 all(
347 not(miri),
348 target_arch = "riscv64",
349 target_feature = "zknd"
350 ) => {
351 unsafe {
353 core::arch::riscv64::aes64ks1i(rs1, rnum as u8)
354 }
355 }
356 _ => { ks::aes64ks1i(rs1, rnum) }
357 }
358}
359
360#[inline(always)]
361#[doc(hidden)]
362#[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
363pub fn aes64ks2(rs1: u64, rs2: u64) -> u64 {
364 cfg_select! {
366 all(
367 not(miri),
368 target_arch = "riscv64",
369 target_feature = "zknd"
370 ) => {
371 unsafe {
373 core::arch::riscv64::aes64ks2(rs1, rs2)
374 }
375 }
376 _ => { ks::aes64ks2(rs1, rs2) }
377 }
378}